mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-28 16:24:04 +02:00
Merge branch 'master' into feature/dope-layout-5543
This commit is contained in:
commit
231c63b703
@ -14,11 +14,12 @@
|
|||||||
#
|
#
|
||||||
class openldap {
|
class openldap {
|
||||||
|
|
||||||
package { ['openldap-servers', 'openldap-clients']:
|
package { [ 'openldap-servers', 'openldap-clients', ]:
|
||||||
ensure => latest,
|
ensure => latest,
|
||||||
}
|
}
|
||||||
|
|
||||||
service { 'slapd':
|
service { 'slapd':
|
||||||
|
enable => true,
|
||||||
ensure => running,
|
ensure => running,
|
||||||
require => Package['openldap-servers'],
|
require => Package['openldap-servers'],
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Class: pgsql
|
# Class: pgsql
|
||||||
#
|
#
|
||||||
# This class installs the postgresql server and client software.
|
# This class installs the PostgreSQL server and client software.
|
||||||
# Further it configures pg_hba.conf to trus the local icinga user.
|
# Further it configures pg_hba.conf to trust the local icinga user.
|
||||||
#
|
#
|
||||||
# Parameters:
|
# Parameters:
|
||||||
#
|
#
|
||||||
@ -17,26 +17,25 @@ class pgsql {
|
|||||||
|
|
||||||
Exec { path => '/sbin:/bin:/usr/bin' }
|
Exec { path => '/sbin:/bin:/usr/bin' }
|
||||||
|
|
||||||
package { [
|
package { [ 'postgresql', 'postgresql-server', ]:
|
||||||
'postgresql', 'postgresql-server'
|
ensure => latest,
|
||||||
]:
|
|
||||||
ensure => latest,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exec { 'initdb':
|
exec { 'initdb':
|
||||||
creates => '/var/lib/pgsql/data/pg_xlog',
|
|
||||||
command => 'service postgresql initdb',
|
command => 'service postgresql initdb',
|
||||||
require => Package['postgresql-server']
|
creates => '/var/lib/pgsql/data/pg_xlog',
|
||||||
|
require => Package['postgresql-server'],
|
||||||
}
|
}
|
||||||
|
|
||||||
service { 'postgresql':
|
service { 'postgresql':
|
||||||
|
enable => true,
|
||||||
ensure => running,
|
ensure => running,
|
||||||
require => [Package['postgresql-server'], Exec['initdb']]
|
require => [ Package['postgresql-server'], Exec['initdb'], ]
|
||||||
}
|
}
|
||||||
|
|
||||||
file { '/var/lib/pgsql/data/pg_hba.conf':
|
file { '/var/lib/pgsql/data/pg_hba.conf':
|
||||||
content => template('pgsql/pg_hba.conf.erb'),
|
content => template('pgsql/pg_hba.conf.erb'),
|
||||||
require => [Package['postgresql-server'], Exec['initdb']],
|
require => [ Package['postgresql-server'], Exec['initdb'], ],
|
||||||
notify => Service['postgresql']
|
notify => Service['postgresql'],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
RELEASE.md
31
RELEASE.md
@ -5,22 +5,47 @@ https://dev.icinga.org/projects/icingaweb2/roadmap
|
|||||||
|
|
||||||
# Release Workflow
|
# Release Workflow
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
|
||||||
Update the [.mailmap](.mailmap) and [AUTHORS](AUTHORS) files:
|
Update the [.mailmap](.mailmap) and [AUTHORS](AUTHORS) files:
|
||||||
|
|
||||||
$ git log --use-mailmap | grep ^Author: | cut -f2- -d' ' | sort | uniq > AUTHORS
|
$ git log --use-mailmap | grep ^Author: | cut -f2- -d' ' | sort | uniq > AUTHORS
|
||||||
|
|
||||||
Update the version number in the [icingaweb2.spec] and [VERSION] files.
|
## Version
|
||||||
|
|
||||||
|
Update the version number in the following files:
|
||||||
|
|
||||||
|
* [icingaweb2.spec] (ensure that the revision is properly set)
|
||||||
|
* [VERSION]
|
||||||
|
* Application Version: [library/Icinga/Application/Version.php]
|
||||||
|
* Module Versions in modules/*/module.info
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
|
||||||
|
VERSION=2.0.0
|
||||||
|
|
||||||
|
vim icingaweb2.spec
|
||||||
|
|
||||||
|
echo "v$VERSION" > VERSION
|
||||||
|
|
||||||
|
sed -i '' "s/const VERSION = '.*'/const VERSION = '$VERSION'/g" library/Icinga/Application/Version.php
|
||||||
|
|
||||||
|
find . -type f -name '*.info' -exec sed -i '' "s/Version: .*/Version: $VERSION/g" {} \;
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
Update the [ChangeLog](ChangeLog) file using
|
Update the [ChangeLog](ChangeLog) file using
|
||||||
the changelog.py script.
|
the changelog.py script.
|
||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
|
|
||||||
$ ./changelog.py --version 2.0.0-rc1
|
$ ./changelog.py --version 2.0.0
|
||||||
|
|
||||||
Wordpress:
|
Wordpress:
|
||||||
|
|
||||||
$ ./changelog.py --version 2.0.0-rc1 --html --links
|
$ ./changelog.py --version 2.0.0 --html --links
|
||||||
|
|
||||||
|
## Git Tag
|
||||||
|
|
||||||
Commit these changes to the "master" branch:
|
Commit these changes to the "master" branch:
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
$Format:%H%d %ci$
|
$Format:%H %ci$
|
||||||
|
@ -3,13 +3,23 @@
|
|||||||
|
|
||||||
namespace Icinga\Controllers;
|
namespace Icinga\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Application\Version;
|
use Icinga\Application\Version;
|
||||||
use Icinga\Web\Controller\ActionController;
|
use Icinga\Web\Controller;
|
||||||
|
|
||||||
class AboutController extends ActionController
|
class AboutController extends Controller
|
||||||
{
|
{
|
||||||
public function indexAction()
|
public function indexAction()
|
||||||
{
|
{
|
||||||
$this->view->version = Version::get();
|
$this->view->version = Version::get();
|
||||||
|
$this->view->modules = Icinga::app()->getModuleManager()->getLoadedModules();
|
||||||
|
$this->view->tabs = $this->getTabs()->add(
|
||||||
|
'about',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('About'),
|
||||||
|
'title' => $this->translate('About Icinga Web 2'),
|
||||||
|
'url' => 'about'
|
||||||
|
)
|
||||||
|
)->activate('about');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@ class ErrorController extends ActionController
|
|||||||
Logger::error($exception);
|
Logger::error($exception);
|
||||||
Logger::error('Stacktrace: %s', $exception->getTraceAsString());
|
Logger::error('Stacktrace: %s', $exception->getTraceAsString());
|
||||||
|
|
||||||
|
if (! ($isAuthenticated = $this->Auth()->isAuthenticated())) {
|
||||||
|
$this->innerLayout = 'error';
|
||||||
|
}
|
||||||
|
|
||||||
switch ($error->type) {
|
switch ($error->type) {
|
||||||
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
|
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
|
||||||
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
|
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
|
||||||
@ -45,11 +49,13 @@ class ErrorController extends ActionController
|
|||||||
$path = array_shift($path);
|
$path = array_shift($path);
|
||||||
$this->getResponse()->setHttpResponseCode(404);
|
$this->getResponse()->setHttpResponseCode(404);
|
||||||
$this->view->message = $this->translate('Page not found.');
|
$this->view->message = $this->translate('Page not found.');
|
||||||
if ($this->Auth()->isAuthenticated() && $modules->hasInstalled($path) && ! $modules->hasEnabled($path)) {
|
if ($isAuthenticated) {
|
||||||
$this->view->message .= ' ' . sprintf(
|
if ($modules->hasInstalled($path) && ! $modules->hasEnabled($path)) {
|
||||||
$this->translate('Enabling the "%s" module might help!'),
|
$this->view->message .= ' ' . sprintf(
|
||||||
$path
|
$this->translate('Enabling the "%s" module might help!'),
|
||||||
);
|
$path
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -93,5 +99,6 @@ class ErrorController extends ActionController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->view->request = $error->request;
|
$this->view->request = $error->request;
|
||||||
|
$this->view->hideControls = ! $isAuthenticated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ use Icinga\Protocol\File\FileReader;
|
|||||||
use Icinga\Web\Controller;
|
use Icinga\Web\Controller;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +31,7 @@ class ListController extends Controller
|
|||||||
'list/'
|
'list/'
|
||||||
. str_replace(' ', '', $action)
|
. str_replace(' ', '', $action)
|
||||||
)
|
)
|
||||||
))->extend(new OutputFormat())->extend(new DashboardAction())->activate($action);
|
))->extend(new OutputFormat())->extend(new DashboardAction())->extend(new MenuAction())->activate($action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,13 +5,13 @@ namespace Icinga\Controllers;
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
use Icinga\Application\Icinga;
|
|
||||||
use Icinga\Exception\NotFoundError;
|
use Icinga\Exception\NotFoundError;
|
||||||
use Icinga\Data\DataArray\ArrayDatasource;
|
use Icinga\Data\DataArray\ArrayDatasource;
|
||||||
use Icinga\Forms\ConfirmRemovalForm;
|
use Icinga\Forms\ConfirmRemovalForm;
|
||||||
use Icinga\Forms\Navigation\NavigationConfigForm;
|
use Icinga\Forms\Navigation\NavigationConfigForm;
|
||||||
use Icinga\Web\Controller;
|
use Icinga\Web\Controller;
|
||||||
use Icinga\Web\Form;
|
use Icinga\Web\Form;
|
||||||
|
use Icinga\Web\Navigation\Navigation;
|
||||||
use Icinga\Web\Notification;
|
use Icinga\Web\Notification;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
@ -21,11 +21,11 @@ use Icinga\Web\Url;
|
|||||||
class NavigationController extends Controller
|
class NavigationController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The default item types provided by Icinga Web 2
|
* The global navigation item type configuration
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $defaultItemTypes;
|
protected $itemTypeConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
@ -33,11 +33,19 @@ class NavigationController extends Controller
|
|||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
parent::init();
|
parent::init();
|
||||||
|
$this->itemTypeConfig = Navigation::getItemTypeConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
$this->defaultItemTypes = array(
|
/**
|
||||||
'menu-item' => $this->translate('Menu Entry'),
|
* Return the label for the given navigation item type
|
||||||
'dashlet' => 'Dashlet'
|
*
|
||||||
);
|
* @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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,33 +55,71 @@ class NavigationController extends Controller
|
|||||||
*/
|
*/
|
||||||
protected function listItemTypes()
|
protected function listItemTypes()
|
||||||
{
|
{
|
||||||
$moduleManager = Icinga::app()->getModuleManager();
|
$types = array();
|
||||||
|
foreach ($this->itemTypeConfig as $type => $options) {
|
||||||
$types = $this->defaultItemTypes;
|
$types[$type] = isset($options['label']) ? $options['label'] : $type;
|
||||||
foreach ($moduleManager->getLoadedModules() as $module) {
|
|
||||||
if ($this->hasPermission($moduleManager::MODULE_PERMISSION_NS . $module->getName())) {
|
|
||||||
$moduleTypes = $module->getNavigationItems();
|
|
||||||
if (! empty($moduleTypes)) {
|
|
||||||
$types = array_merge($types, $moduleTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $types;
|
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->where('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
|
* Show the current user a list of his/her navigation items
|
||||||
*/
|
*/
|
||||||
public function indexAction()
|
public function indexAction()
|
||||||
{
|
{
|
||||||
$user = $this->Auth()->getUser();
|
$user = $this->Auth()->getUser();
|
||||||
|
|
||||||
$ds = new ArrayDatasource(array_merge(
|
$ds = new ArrayDatasource(array_merge(
|
||||||
Config::app('navigation')->select()->where('owner', $user->getUsername())->fetchAll(),
|
$this->fetchSharedNavigationItemConfigs($user->getUsername()),
|
||||||
iterator_to_array($user->loadNavigationConfig())
|
$this->fetchUserNavigationItemConfigs($user->getUsername())
|
||||||
));
|
));
|
||||||
$ds->setKeyColumn('name');
|
|
||||||
$query = $ds->select();
|
$query = $ds->select();
|
||||||
|
|
||||||
$this->view->types = $this->listItemTypes();
|
$this->view->types = $this->listItemTypes();
|
||||||
@ -91,7 +137,7 @@ class NavigationController extends Controller
|
|||||||
array(
|
array(
|
||||||
'type' => $this->translate('Type'),
|
'type' => $this->translate('Type'),
|
||||||
'owner' => $this->translate('Shared'),
|
'owner' => $this->translate('Shared'),
|
||||||
'name' => $this->translate('Shared Navigation')
|
'name' => $this->translate('Navigation')
|
||||||
),
|
),
|
||||||
$query
|
$query
|
||||||
);
|
);
|
||||||
@ -103,13 +149,11 @@ class NavigationController extends Controller
|
|||||||
public function sharedAction()
|
public function sharedAction()
|
||||||
{
|
{
|
||||||
$this->assertPermission('config/application/navigation');
|
$this->assertPermission('config/application/navigation');
|
||||||
$config = Config::app('navigation');
|
$ds = new ArrayDatasource($this->fetchSharedNavigationItemConfigs());
|
||||||
$config->getConfigObject()->setKeyColumn('name');
|
$query = $ds->select();
|
||||||
$query = $config->select();
|
|
||||||
|
|
||||||
$removeForm = new Form();
|
$removeForm = new Form();
|
||||||
$removeForm->setUidDisabled();
|
$removeForm->setUidDisabled();
|
||||||
$removeForm->setAction(Url::fromPath('navigation/unshare'));
|
|
||||||
$removeForm->addElement('hidden', 'name', array(
|
$removeForm->addElement('hidden', 'name', array(
|
||||||
'decorators' => array('ViewHelper')
|
'decorators' => array('ViewHelper')
|
||||||
));
|
));
|
||||||
@ -156,11 +200,14 @@ class NavigationController extends Controller
|
|||||||
{
|
{
|
||||||
$form = new NavigationConfigForm();
|
$form = new NavigationConfigForm();
|
||||||
$form->setRedirectUrl('navigation');
|
$form->setRedirectUrl('navigation');
|
||||||
|
$form->setUser($this->Auth()->getUser());
|
||||||
$form->setItemTypes($this->listItemTypes());
|
$form->setItemTypes($this->listItemTypes());
|
||||||
$form->setTitle($this->translate('Create New Navigation Item'));
|
$form->setTitle($this->translate('Create New Navigation Item'));
|
||||||
$form->addDescription($this->translate('Create a new navigation item, such as a menu entry or dashlet.'));
|
$form->addDescription($this->translate('Create a new navigation item, such as a menu entry or dashlet.'));
|
||||||
$form->setUser($this->Auth()->getUser());
|
|
||||||
$form->setShareConfig(Config::app('navigation'));
|
// TODO: Fetch all "safe" parameters from the url and populate them
|
||||||
|
$form->populate(array('url' => rawurldecode($this->params->get('url', ''))));
|
||||||
|
|
||||||
$form->setOnSuccess(function (NavigationConfigForm $form) {
|
$form->setOnSuccess(function (NavigationConfigForm $form) {
|
||||||
$data = array_filter($form->getValues());
|
$data = array_filter($form->getValues());
|
||||||
|
|
||||||
@ -172,7 +219,7 @@ class NavigationController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($form->save()) {
|
if ($form->save()) {
|
||||||
if (isset($data['type']) && $data['type'] === 'menu-item') {
|
if ($data['type'] === 'menu-item') {
|
||||||
$form->getResponse()->setRerenderLayout();
|
$form->getResponse()->setRerenderLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,14 +241,22 @@ class NavigationController extends Controller
|
|||||||
public function editAction()
|
public function editAction()
|
||||||
{
|
{
|
||||||
$itemName = $this->params->getRequired('name');
|
$itemName = $this->params->getRequired('name');
|
||||||
|
$itemType = $this->params->getRequired('type');
|
||||||
$referrer = $this->params->get('referrer', 'index');
|
$referrer = $this->params->get('referrer', 'index');
|
||||||
|
|
||||||
|
$user = $this->Auth()->getUser();
|
||||||
|
if ($user->can('config/application/navigation')) {
|
||||||
|
$itemOwner = $this->params->get('owner', $user->getUsername());
|
||||||
|
} else {
|
||||||
|
$itemOwner = $user->getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
$form = new NavigationConfigForm();
|
$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->setRedirectUrl($referrer === 'shared' ? 'navigation/shared' : 'navigation');
|
||||||
$form->setItemTypes($this->listItemTypes());
|
$form->setTitle(sprintf($this->translate('Edit %s %s'), $this->getItemLabel($itemType), $itemName));
|
||||||
$form->setTitle(sprintf($this->translate('Edit Navigation Item %s'), $itemName));
|
|
||||||
$form->setUser($this->Auth()->getUser());
|
|
||||||
$form->setShareConfig(Config::app('navigation'));
|
|
||||||
$form->setOnSuccess(function (NavigationConfigForm $form) use ($itemName) {
|
$form->setOnSuccess(function (NavigationConfigForm $form) use ($itemName) {
|
||||||
$data = array_map(
|
$data = array_map(
|
||||||
function ($v) {
|
function ($v) {
|
||||||
@ -248,13 +303,17 @@ class NavigationController extends Controller
|
|||||||
public function removeAction()
|
public function removeAction()
|
||||||
{
|
{
|
||||||
$itemName = $this->params->getRequired('name');
|
$itemName = $this->params->getRequired('name');
|
||||||
|
$itemType = $this->params->getRequired('type');
|
||||||
|
$user = $this->Auth()->getUser();
|
||||||
|
|
||||||
$navigationConfigForm = new NavigationConfigForm();
|
$navigationConfigForm = new NavigationConfigForm();
|
||||||
$navigationConfigForm->setUser($this->Auth()->getUser());
|
$navigationConfigForm->setUser($user);
|
||||||
$navigationConfigForm->setShareConfig(Config::app('navigation'));
|
$navigationConfigForm->setShareConfig(Config::navigation($itemType));
|
||||||
|
$navigationConfigForm->setUserConfig(Config::navigation($itemType, $user->getUsername()));
|
||||||
|
|
||||||
$form = new ConfirmRemovalForm();
|
$form = new ConfirmRemovalForm();
|
||||||
$form->setRedirectUrl('navigation');
|
$form->setRedirectUrl('navigation');
|
||||||
$form->setTitle(sprintf($this->translate('Remove Navigation Item %s'), $itemName));
|
$form->setTitle(sprintf($this->translate('Remove %s %s'), $this->getItemLabel($itemType), $itemName));
|
||||||
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($itemName, $navigationConfigForm) {
|
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($itemName, $navigationConfigForm) {
|
||||||
try {
|
try {
|
||||||
$itemConfig = $navigationConfigForm->delete($itemName);
|
$itemConfig = $navigationConfigForm->delete($itemName);
|
||||||
@ -291,9 +350,14 @@ class NavigationController extends Controller
|
|||||||
$this->assertPermission('config/application/navigation');
|
$this->assertPermission('config/application/navigation');
|
||||||
$this->assertHttpMethod('POST');
|
$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 = new NavigationConfigForm();
|
||||||
$navigationConfigForm->setUser($this->Auth()->getUser());
|
$navigationConfigForm->setUser($this->Auth()->getUser());
|
||||||
$navigationConfigForm->setShareConfig(Config::app('navigation'));
|
$navigationConfigForm->setShareConfig(Config::navigation($itemType));
|
||||||
|
$navigationConfigForm->setUserConfig(Config::navigation($itemType, $itemOwner));
|
||||||
|
|
||||||
$form = new Form(array(
|
$form = new Form(array(
|
||||||
'onSuccess' => function ($form) use ($navigationConfigForm) {
|
'onSuccess' => function ($form) use ($navigationConfigForm) {
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
namespace Icinga\Forms\Config\Resource;
|
namespace Icinga\Forms\Config\Resource;
|
||||||
|
|
||||||
use Icinga\Web\Form;
|
|
||||||
use Icinga\Application\Platform;
|
use Icinga\Application\Platform;
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form class for adding/modifying database resources
|
* Form class for adding/modifying database resources
|
||||||
@ -43,12 +43,30 @@ class DbResourceForm extends Form
|
|||||||
$dbChoices['oci'] = 'Oracle (OCI8)';
|
$dbChoices['oci'] = 'Oracle (OCI8)';
|
||||||
}
|
}
|
||||||
$offerPostgres = false;
|
$offerPostgres = false;
|
||||||
|
$offerMysql = false;
|
||||||
if (isset($formData['db'])) {
|
if (isset($formData['db'])) {
|
||||||
if ($formData['db'] === 'pgsql') {
|
if ($formData['db'] === 'pgsql') {
|
||||||
$offerPostgres = true;
|
$offerPostgres = true;
|
||||||
|
} elseif ($formData['db'] === 'mysql') {
|
||||||
|
$offerMysql = true;
|
||||||
}
|
}
|
||||||
} elseif (key($dbChoices) === 'pgsql') {
|
} else {
|
||||||
$offerPostgres = true;
|
$dbChoice = key($dbChoices);
|
||||||
|
if ($dbChoice === 'pgsql') {
|
||||||
|
$offerPostgres = true;
|
||||||
|
} elseif ($dbChoices === 'mysql') {
|
||||||
|
$offerMysql = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$socketInfo = '';
|
||||||
|
if ($offerPostgres) {
|
||||||
|
$socketInfo = $this->translate(
|
||||||
|
'For using unix domain sockets, specify the path to the unix domain socket directory'
|
||||||
|
);
|
||||||
|
} elseif ($offerMysql) {
|
||||||
|
$socketInfo = $this->translate(
|
||||||
|
'For using unix domain sockets, specify localhost'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
'text',
|
'text',
|
||||||
@ -76,7 +94,8 @@ class DbResourceForm extends Form
|
|||||||
array (
|
array (
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'label' => $this->translate('Host'),
|
'label' => $this->translate('Host'),
|
||||||
'description' => $this->translate('The hostname of the database'),
|
'description' => $this->translate('The hostname of the database')
|
||||||
|
. ($socketInfo ? '. ' . $socketInfo : ''),
|
||||||
'value' => 'localhost'
|
'value' => 'localhost'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -119,6 +138,14 @@ class DbResourceForm extends Form
|
|||||||
'description' => $this->translate('The password to use for authentication')
|
'description' => $this->translate('The password to use for authentication')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'charset',
|
||||||
|
array (
|
||||||
|
'description' => $this->translate('The character set for the database'),
|
||||||
|
'label' => $this->translate('Character Set')
|
||||||
|
)
|
||||||
|
);
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
'checkbox',
|
'checkbox',
|
||||||
'persistent',
|
'persistent',
|
||||||
|
@ -123,12 +123,18 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
/**
|
/**
|
||||||
* Return the user's navigation configuration
|
* Return the user's navigation configuration
|
||||||
*
|
*
|
||||||
|
* @param string $type
|
||||||
|
*
|
||||||
* @return Config
|
* @return Config
|
||||||
*/
|
*/
|
||||||
public function getUserConfig()
|
public function getUserConfig($type = null)
|
||||||
{
|
{
|
||||||
if ($this->userConfig === null) {
|
if ($this->userConfig === null) {
|
||||||
$this->setUserConfig($this->getUser()->loadNavigationConfig());
|
if ($type === null) {
|
||||||
|
throw new ProgrammingError('You need to pass a type if no user configuration is set');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setUserConfig(Config::navigation($type, $this->getUser()->getUsername()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->userConfig;
|
return $this->userConfig;
|
||||||
@ -151,10 +157,20 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
/**
|
/**
|
||||||
* Return the shared navigation configuration
|
* Return the shared navigation configuration
|
||||||
*
|
*
|
||||||
|
* @param string $type
|
||||||
|
*
|
||||||
* @return Config
|
* @return Config
|
||||||
*/
|
*/
|
||||||
public function getShareConfig()
|
public function getShareConfig($type = null)
|
||||||
{
|
{
|
||||||
|
if ($this->shareConfig === null) {
|
||||||
|
if ($type === null) {
|
||||||
|
throw new ProgrammingError('You need to pass a type if no share configuration is set');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setShareConfig(Config::navigation($type));
|
||||||
|
}
|
||||||
|
|
||||||
return $this->shareConfig;
|
return $this->shareConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,10 +210,9 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
$children = $this->itemToLoad ? $this->getFlattenedChildren($this->itemToLoad) : array();
|
$children = $this->itemToLoad ? $this->getFlattenedChildren($this->itemToLoad) : array();
|
||||||
|
|
||||||
$names = array();
|
$names = array();
|
||||||
foreach ($this->getShareConfig() as $sectionName => $sectionConfig) {
|
foreach ($this->getShareConfig($type) as $sectionName => $sectionConfig) {
|
||||||
if (
|
if (
|
||||||
$sectionName !== $this->itemToLoad
|
$sectionName !== $this->itemToLoad
|
||||||
&& $sectionConfig->type === $type
|
|
||||||
&& $sectionConfig->owner === ($owner ?: $this->getUser()->getUsername())
|
&& $sectionConfig->owner === ($owner ?: $this->getUser()->getUsername())
|
||||||
&& !in_array($sectionName, $children, true)
|
&& !in_array($sectionName, $children, true)
|
||||||
) {
|
) {
|
||||||
@ -205,10 +220,9 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->getUserConfig() as $sectionName => $sectionConfig) {
|
foreach ($this->getUserConfig($type) as $sectionName => $sectionConfig) {
|
||||||
if (
|
if (
|
||||||
$sectionName !== $this->itemToLoad
|
$sectionName !== $this->itemToLoad
|
||||||
&& $sectionConfig->type === $type
|
|
||||||
&& !in_array($sectionName, $children, true)
|
&& !in_array($sectionName, $children, true)
|
||||||
) {
|
) {
|
||||||
$names[] = $sectionName;
|
$names[] = $sectionName;
|
||||||
@ -271,29 +285,31 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*
|
*
|
||||||
* @throws InvalidArgumentException In case $data does not contain a navigation item name
|
* @throws InvalidArgumentException In case $data does not contain a navigation item name or type
|
||||||
* @throws IcingaException In case a navigation item with the same name already exists
|
* @throws IcingaException In case a navigation item with the same name already exists
|
||||||
*/
|
*/
|
||||||
public function add(array $data)
|
public function add(array $data)
|
||||||
{
|
{
|
||||||
if (! isset($data['name'])) {
|
if (! isset($data['name'])) {
|
||||||
throw new InvalidArgumentException('Key \'name\' missing');
|
throw new InvalidArgumentException('Key \'name\' missing');
|
||||||
|
} elseif (! isset($data['type'])) {
|
||||||
|
throw new InvalidArgumentException('Key \'type\' missing');
|
||||||
}
|
}
|
||||||
|
|
||||||
$shared = false;
|
$shared = false;
|
||||||
$config = $this->getUserConfig();
|
$config = $this->getUserConfig($data['type']);
|
||||||
if ((isset($data['users']) && $data['users']) || (isset($data['groups']) && $data['groups'])) {
|
if ((isset($data['users']) && $data['users']) || (isset($data['groups']) && $data['groups'])) {
|
||||||
if ($this->getUser()->can('application/share/navigation')) {
|
if ($this->getUser()->can('application/share/navigation')) {
|
||||||
$data['owner'] = $this->getUser()->getUsername();
|
$data['owner'] = $this->getUser()->getUsername();
|
||||||
$config = $this->getShareConfig();
|
$config = $this->getShareConfig($data['type']);
|
||||||
$shared = true;
|
$shared = true;
|
||||||
} else {
|
} else {
|
||||||
unset($data['users']);
|
unset($data['users']);
|
||||||
unset($data['groups']);
|
unset($data['groups']);
|
||||||
}
|
}
|
||||||
} elseif (isset($data['parent']) && $data['parent'] && $this->hasBeenShared($data['parent'])) {
|
} elseif (isset($data['parent']) && $data['parent'] && $this->hasBeenShared($data['parent'], $data['type'])) {
|
||||||
$data['owner'] = $this->getUser()->getUsername();
|
$data['owner'] = $this->getUser()->getUsername();
|
||||||
$config = $this->getShareConfig();
|
$config = $this->getShareConfig($data['type']);
|
||||||
$shared = true;
|
$shared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,9 +317,9 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
$exists = $config->hasSection($itemName);
|
$exists = $config->hasSection($itemName);
|
||||||
if (! $exists) {
|
if (! $exists) {
|
||||||
if ($shared) {
|
if ($shared) {
|
||||||
$exists = $this->getUserConfig()->hasSection($itemName);
|
$exists = $this->getUserConfig($data['type'])->hasSection($itemName);
|
||||||
} else {
|
} else {
|
||||||
$exists = (bool) $this->getShareConfig()
|
$exists = (bool) $this->getShareConfig($data['type'])
|
||||||
->select()
|
->select()
|
||||||
->where('name', $itemName)
|
->where('name', $itemName)
|
||||||
->where('owner', $this->getUser()->getUsername())
|
->where('owner', $this->getUser()->getUsername())
|
||||||
@ -385,8 +401,7 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
if ($ownerName === $this->getUser()->getUsername()) {
|
if ($ownerName === $this->getUser()->getUsername()) {
|
||||||
$exists = $this->getUserConfig()->hasSection($name);
|
$exists = $this->getUserConfig()->hasSection($name);
|
||||||
} else {
|
} else {
|
||||||
$owner = new User($ownerName);
|
$exists = Config::navigation($itemConfig->type, $ownerName)->hasSection($name);
|
||||||
$exists = $owner->loadNavigationConfig()->hasSection($name);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$exists = (bool) $this->getShareConfig()
|
$exists = (bool) $this->getShareConfig()
|
||||||
@ -521,8 +536,7 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
if (! $itemConfig->owner || $itemConfig->owner === $this->getUser()->getUsername()) {
|
if (! $itemConfig->owner || $itemConfig->owner === $this->getUser()->getUsername()) {
|
||||||
$config = $this->getUserConfig();
|
$config = $this->getUserConfig();
|
||||||
} else {
|
} else {
|
||||||
$owner = new User($itemConfig->owner);
|
$config = Config::navigation($itemConfig->type, $itemConfig->owner);
|
||||||
$config = $owner->loadNavigationConfig();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($children as $child) {
|
foreach ($children as $child) {
|
||||||
@ -549,6 +563,13 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
$shared = false;
|
$shared = false;
|
||||||
$itemTypes = $this->getItemTypes();
|
$itemTypes = $this->getItemTypes();
|
||||||
$itemType = isset($formData['type']) ? $formData['type'] : key($itemTypes);
|
$itemType = isset($formData['type']) ? $formData['type'] : key($itemTypes);
|
||||||
|
if ($itemType === null) {
|
||||||
|
throw new ProgrammingError(
|
||||||
|
'This should actually not happen. Create a bug report at dev.icinga.org'
|
||||||
|
. ' or remove this assertion if you know what you\'re doing'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$itemForm = $this->getItemForm($itemType);
|
$itemForm = $this->getItemForm($itemType);
|
||||||
|
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
@ -606,17 +627,27 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addElement(
|
if (empty($itemTypes) || count($itemTypes) === 1) {
|
||||||
'select',
|
$this->addElement(
|
||||||
'type',
|
'hidden',
|
||||||
array(
|
'type',
|
||||||
'required' => true,
|
array(
|
||||||
'autosubmit' => true,
|
'value' => $itemType
|
||||||
'label' => $this->translate('Type'),
|
)
|
||||||
'description' => $this->translate('The type of this navigation item'),
|
);
|
||||||
'multiOptions' => $itemTypes
|
} else {
|
||||||
)
|
$this->addElement(
|
||||||
);
|
'select',
|
||||||
|
'type',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'autosubmit' => true,
|
||||||
|
'label' => $this->translate('Type'),
|
||||||
|
'description' => $this->translate('The type of this navigation item'),
|
||||||
|
'multiOptions' => $itemTypes
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (! $shared && $itemForm->requiresParentSelection()) {
|
if (! $shared && $itemForm->requiresParentSelection()) {
|
||||||
if ($this->itemToLoad && $this->hasBeenShared($this->itemToLoad)) {
|
if ($this->itemToLoad && $this->hasBeenShared($this->itemToLoad)) {
|
||||||
@ -767,12 +798,13 @@ class NavigationConfigForm extends ConfigForm
|
|||||||
* Return whether the given navigation item has been shared
|
* Return whether the given navigation item has been shared
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
|
* @param string $type
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function hasBeenShared($name)
|
protected function hasBeenShared($name, $type = null)
|
||||||
{
|
{
|
||||||
return $this->getConfigForItem($name) === $this->getShareConfig();
|
return $this->getShareConfig($type) === $this->getConfigForItem($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
namespace Icinga\Forms\Navigation;
|
namespace Icinga\Forms\Navigation;
|
||||||
|
|
||||||
use Icinga\Web\Form;
|
use Icinga\Web\Form;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
class NavigationItemForm extends Form
|
class NavigationItemForm extends Form
|
||||||
{
|
{
|
||||||
@ -71,4 +72,20 @@ class NavigationItemForm extends Form
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getValues($suppressArrayNotation = false)
|
||||||
|
{
|
||||||
|
$values = parent::getValues($suppressArrayNotation);
|
||||||
|
if (isset($values['url']) && $values['url']) {
|
||||||
|
$url = Url::fromPath($values['url']);
|
||||||
|
if (! $url->isExternal() && ($relativePath = $url->getRelativeUrl())) {
|
||||||
|
$values['url'] = $relativePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
8
application/layouts/scripts/error.phtml
Normal file
8
application/layouts/scripts/error.phtml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<div class="logo">
|
||||||
|
<div class="image">
|
||||||
|
<img aria-hidden="true" src="<?= $this->baseUrl('img/logo_icinga_big.png'); ?>" alt="<?= $this->translate('The Icinga logo'); ?>" >
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="below-logo">
|
||||||
|
<?= $this->render('inline.phtml') ?>
|
||||||
|
</div>
|
@ -1,25 +1,128 @@
|
|||||||
<div class="content">
|
<div class="controls">
|
||||||
<h1>Icinga Web 2</h1>
|
<?= $tabs; ?>
|
||||||
<?php
|
</div>
|
||||||
$versionInfo = array();
|
<div class="content about">
|
||||||
if ($version !== false) {
|
<?= $this->img(
|
||||||
foreach (array(
|
'img/logo_icinga_big_dark.png',
|
||||||
'appVersion' => $this->translate('Version: %s'),
|
null,
|
||||||
'gitCommitID' => $this->translate('Git commit ID: %s'),
|
array(
|
||||||
'gitCommitDate' => $this->translate('Git commit date: %s')
|
'width' => 400,
|
||||||
) as $key => $label) {
|
'class' => 'about-logo'
|
||||||
if (array_key_exists($key, $version) && null !== ($value = $version[$key])) {
|
)
|
||||||
$versionInfo[] = sprintf($label, htmlspecialchars($value));
|
); ?>
|
||||||
}
|
<p class="about-version">
|
||||||
}
|
<?php if (isset($version['appVersion'])): ?>
|
||||||
}
|
<strong><?= $this->translate('Version'); ?>:</strong> <?= $this->escape($version['appVersion']); ?>
|
||||||
|
<?php endif ?>
|
||||||
echo (
|
<?php if (isset($version['gitCommitID'])): ?>
|
||||||
0 === count($versionInfo)
|
<br>
|
||||||
? '<p class="message-error">' . $this->translate(
|
<strong><?= $this->translate('Git commit ID'); ?>:</strong> <?= $this->escape($version['gitCommitID']); ?>
|
||||||
'Can\'t determine Icinga Web 2\'s version'
|
<?php endif ?>
|
||||||
)
|
<?php if (isset($version['gitCommitDate'])): ?>
|
||||||
: '<p>' . nl2br(implode("\n", $versionInfo), false)
|
<br>
|
||||||
) . '</p>';
|
<strong><?= $this->translate('Git commit date'); ?>:</strong> <?= $this->escape($version['gitCommitDate']); ?>
|
||||||
?>
|
<?php endif ?>
|
||||||
|
</p>
|
||||||
|
<p class="about-license">
|
||||||
|
<strong><?= $this->translate('Copyright'); ?></strong>: © 2013-<?= date('Y'); ?> <?= $this->qlink(
|
||||||
|
$this->translate('The Icinga Project'),
|
||||||
|
'https://www.icinga.org',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank'
|
||||||
|
)
|
||||||
|
); ?>
|
||||||
|
<br>
|
||||||
|
<strong><?= $this->translate('License'); ?></strong>: GNU GPL v2+
|
||||||
|
</p>
|
||||||
|
<p class="about-social">
|
||||||
|
<?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://www.twitter.com/icinga',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'twitter',
|
||||||
|
'title' => $this->translate('Icinga on Twitter')
|
||||||
|
)
|
||||||
|
); ?> <?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://www.facebook.com/icinga',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'facebook-squared',
|
||||||
|
'title' => $this->translate('Icinga on Facebook')
|
||||||
|
)
|
||||||
|
); ?>
|
||||||
|
</p>
|
||||||
|
<div class="about-urls">
|
||||||
|
<div><?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://dev.icinga.org/projects/icingaweb2',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'img' => 'img/bugreport.png',
|
||||||
|
'title' => $this->translate('Report a bug')
|
||||||
|
)
|
||||||
|
); ?> <?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://www.icinga.org/services/support',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'img' => 'img/support.png',
|
||||||
|
'title' => $this->translate('Support / Mailinglists')
|
||||||
|
)
|
||||||
|
); ?></div>
|
||||||
|
<div><?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://wiki.icinga.org',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'img' => 'img/wiki.png',
|
||||||
|
'title' => $this->translate('Icinga Wiki')
|
||||||
|
)
|
||||||
|
); ?> <?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://docs.icinga.org/',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'img' => 'img/docs.png',
|
||||||
|
'title' => $this->translate('Icinga Documentation')
|
||||||
|
)
|
||||||
|
); ?></div>
|
||||||
|
</div>
|
||||||
|
<h2><?= $this->translate('Loaded modules') ?></h2>
|
||||||
|
<table class="action alternating about-modules" data-base-target="_next">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><?= $this->translate('Name') ?></th>
|
||||||
|
<th><?= $this->translate('Version') ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($modules as $module): ?>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<?php if ($this->hasPermission('config/modules')): ?>
|
||||||
|
<?= $this->qlink(
|
||||||
|
$module->getName(),
|
||||||
|
'config/module/',
|
||||||
|
array('name' => $module->getName()),
|
||||||
|
array('title' => sprintf($this->translate('Show the overview of the %s module'), $module->getName()))
|
||||||
|
); ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<?= $this->escape($module->getName()); ?>
|
||||||
|
<?php endif ?>
|
||||||
|
<td>
|
||||||
|
<?= $this->escape($module->getVersion()); ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
<?php if (! $hideControls): ?>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
<?= $tabs->showOnlyCloseButton(); ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
|
||||||
<p><strong><?= nl2br($this->escape($message)) ?></strong></p>
|
|
||||||
<?php if (isset($stackTrace)) : ?>
|
|
||||||
<hr />
|
|
||||||
<pre><?= $this->escape($stackTrace) ?></pre>
|
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
<div class="content">
|
||||||
|
<p><strong><?= nl2br($this->escape($message)); ?></strong></p>
|
||||||
|
<?php if (isset($stackTrace)): ?>
|
||||||
|
<hr />
|
||||||
|
<pre><?= $this->escape($stackTrace) ?></pre>
|
||||||
|
<?php endif ?>
|
||||||
|
</div>
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use Icinga\Data\Extensible;
|
use Icinga\Data\Extensible;
|
||||||
use Icinga\Data\Updatable;
|
use Icinga\Data\Updatable;
|
||||||
|
use Icinga\Data\Selectable;
|
||||||
|
|
||||||
$extensible = $this->hasPermission('config/authentication/groups/add') && $backend instanceof Extensible;
|
$extensible = $this->hasPermission('config/authentication/groups/add') && $backend instanceof Extensible;
|
||||||
|
|
||||||
@ -67,7 +68,22 @@ foreach ($members as $member): ?>
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="member-name"><?= $this->escape($member->user_name); ?></td>
|
<td class="member-name">
|
||||||
|
<?php if (
|
||||||
|
$this->hasPermission('config/authentication/users/show')
|
||||||
|
&& ($userBackend = $backend->getUserBackend()) !== null
|
||||||
|
&& $userBackend instanceof Selectable
|
||||||
|
): ?>
|
||||||
|
<?= $this->qlink($member->user_name, 'user/show', array(
|
||||||
|
'backend' => $userBackend->getName(),
|
||||||
|
'user' => $member->user_name
|
||||||
|
), array(
|
||||||
|
'title' => sprintf($this->translate('Show detailed information about %s'), $member->user_name)
|
||||||
|
)); ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<?= $this->escape($member->user_name); ?>
|
||||||
|
<?php endif ?>
|
||||||
|
</td>
|
||||||
<?php if (isset($removeForm)): ?>
|
<?php if (isset($removeForm)): ?>
|
||||||
<td class="member-remove" data-base-target="_self">
|
<td class="member-remove" data-base-target="_self">
|
||||||
<?php $removeForm->getElement('user_name')->setValue($member->user_name); echo $removeForm; ?>
|
<?php $removeForm->getElement('user_name')->setValue($member->user_name); echo $removeForm; ?>
|
||||||
|
@ -22,14 +22,17 @@
|
|||||||
<th style="width: 5em"><?= $this->translate('Remove'); ?></th>
|
<th style="width: 5em"><?= $this->translate('Remove'); ?></th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($items as $name => $item): ?>
|
<?php foreach ($items as $item): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= $this->qlink(
|
<td><?= $this->qlink(
|
||||||
$name,
|
$item->name,
|
||||||
'navigation/edit',
|
'navigation/edit',
|
||||||
array('name' => $name),
|
|
||||||
array(
|
array(
|
||||||
'title' => sprintf($this->translate('Edit navigation item %s'), $name)
|
'name' => $item->name,
|
||||||
|
'type' => $item->type
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => sprintf($this->translate('Edit navigation item %s'), $item->name)
|
||||||
)
|
)
|
||||||
); ?></td>
|
); ?></td>
|
||||||
<td><?= $item->type && isset($types[$item->type])
|
<td><?= $item->type && isset($types[$item->type])
|
||||||
@ -39,10 +42,13 @@
|
|||||||
<td><?= $this->qlink(
|
<td><?= $this->qlink(
|
||||||
'',
|
'',
|
||||||
'navigation/remove',
|
'navigation/remove',
|
||||||
array('name' => $name),
|
array(
|
||||||
|
'name' => $item->name,
|
||||||
|
'type' => $item->type
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'icon' => 'trash',
|
'icon' => 'trash',
|
||||||
'title' => sprintf($this->translate('Remove navigation item %s'), $name)
|
'title' => sprintf($this->translate('Remove navigation item %s'), $item->name)
|
||||||
)
|
)
|
||||||
); ?></td>
|
); ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
<?php if (! $this->compact): ?>
|
<?php
|
||||||
|
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
|
if (! $this->compact): ?>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<?= $this->tabs; ?>
|
<?= $this->tabs; ?>
|
||||||
<?= $this->sortBox; ?>
|
<?= $this->sortBox; ?>
|
||||||
@ -19,17 +23,19 @@
|
|||||||
<th style="width: 5em"><?= $this->translate('Unshare'); ?></th>
|
<th style="width: 5em"><?= $this->translate('Unshare'); ?></th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($items as $name => $item): ?>
|
<?php foreach ($items as $item): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= $this->qlink(
|
<td><?= $this->qlink(
|
||||||
$name,
|
$item->name,
|
||||||
'navigation/edit',
|
'navigation/edit',
|
||||||
array(
|
array(
|
||||||
'name' => $name,
|
'name' => $item->name,
|
||||||
|
'type' => $item->type,
|
||||||
|
'owner' => $item->owner,
|
||||||
'referrer' => 'shared'
|
'referrer' => 'shared'
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'title' => sprintf($this->translate('Edit shared navigation item %s'), $name)
|
'title' => sprintf($this->translate('Edit shared navigation item %s'), $item->name)
|
||||||
)
|
)
|
||||||
); ?></td>
|
); ?></td>
|
||||||
<td><?= $item->type && isset($types[$item->type])
|
<td><?= $item->type && isset($types[$item->type])
|
||||||
@ -48,7 +54,12 @@
|
|||||||
)
|
)
|
||||||
); ?></td>
|
); ?></td>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<td data-base-target="_self"><?= $removeForm->setDefault('name', $name); ?></td>
|
<td data-base-target="_self"><?= $removeForm
|
||||||
|
->setDefault('name', $item->name)
|
||||||
|
->setAction(Url::fromPath(
|
||||||
|
'navigation/unshare',
|
||||||
|
array('type' => $item->type, 'owner' => $item->owner)
|
||||||
|
)); ?></td>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
@ -19,21 +19,38 @@ to handle authentication and authorization, monitoring data or user preferences.
|
|||||||
Directive | Description
|
Directive | Description
|
||||||
----------------|------------
|
----------------|------------
|
||||||
**type** | `db`
|
**type** | `db`
|
||||||
**db** | Database management system. Either `mysql` or `pgsql`.
|
**db** | Database management system. In most cases `mysql` or `pgsql`.
|
||||||
**host** | Connect to the database server on the given host.
|
**host** | Connect to the database server on the given host. For using unix domain sockets, specify `localhost` for MySQL and the path to the unix domain socket directory for PostgreSQL.
|
||||||
**port** | Port number to use for the connection.
|
**port** | Port number to use. Mandatory for connections to a PostgreSQL database.
|
||||||
**username** | The username to use when connecting to the server.
|
**username** | The username to use when connecting to the server.
|
||||||
**password** | The password to use when connecting to the server.
|
**password** | The password to use when connecting to the server.
|
||||||
**dbname** | The database to use.
|
**dbname** | The database to use.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```
|
````
|
||||||
[icingaweb]
|
[icingaweb-mysql-tcp]
|
||||||
|
type = db
|
||||||
|
db = mysql
|
||||||
|
host = 127.0.0.1
|
||||||
|
port = 3306
|
||||||
|
username = icingaweb
|
||||||
|
password = icingaweb
|
||||||
|
dbname = icingaweb
|
||||||
|
|
||||||
|
[icingaweb-mysql-socket]
|
||||||
type = db
|
type = db
|
||||||
db = mysql
|
db = mysql
|
||||||
host = localhost
|
host = localhost
|
||||||
port = 3306
|
username = icingaweb
|
||||||
|
password = icingaweb
|
||||||
|
dbname = icingaweb
|
||||||
|
|
||||||
|
[icingaweb-pgsql-socket]
|
||||||
|
type = db
|
||||||
|
db = pgsql
|
||||||
|
host = /var/run/postgresql
|
||||||
|
port = 5432
|
||||||
username = icingaweb
|
username = icingaweb
|
||||||
password = icingaweb
|
password = icingaweb
|
||||||
dbname = icingaweb
|
dbname = icingaweb
|
||||||
|
@ -13,7 +13,9 @@ use Icinga\Data\Selectable;
|
|||||||
use Icinga\Data\SimpleQuery;
|
use Icinga\Data\SimpleQuery;
|
||||||
use Icinga\File\Ini\IniWriter;
|
use Icinga\File\Ini\IniWriter;
|
||||||
use Icinga\File\Ini\IniParser;
|
use Icinga\File\Ini\IniParser;
|
||||||
|
use Icinga\Exception\IcingaException;
|
||||||
use Icinga\Exception\NotReadableError;
|
use Icinga\Exception\NotReadableError;
|
||||||
|
use Icinga\Web\Navigation\Navigation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container for INI like configuration and global registry of application and module related configuration.
|
* Container for INI like configuration and global registry of application and module related configuration.
|
||||||
@ -41,6 +43,13 @@ class Config implements Countable, Iterator, Selectable
|
|||||||
*/
|
*/
|
||||||
protected static $modules = array();
|
protected static $modules = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigation config instances per type
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected static $navigation = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The internal ConfigObject
|
* The internal ConfigObject
|
||||||
*
|
*
|
||||||
@ -416,6 +425,60 @@ class Config implements Countable, Iterator, Selectable
|
|||||||
return $moduleConfigs[$configname];
|
return $moduleConfigs[$configname];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a navigation config
|
||||||
|
*
|
||||||
|
* @param string $type The type identifier of the navigation item for which to return its config
|
||||||
|
* @param string $username A user's name or null if the shared config is desired
|
||||||
|
* @param bool $fromDisk If true, the configuration will be read from disk
|
||||||
|
*
|
||||||
|
* @return Config The requested configuration
|
||||||
|
*/
|
||||||
|
public static function navigation($type, $username = null, $fromDisk = false)
|
||||||
|
{
|
||||||
|
if (! isset(self::$navigation[$type])) {
|
||||||
|
self::$navigation[$type] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$branch = $username ?: 'shared';
|
||||||
|
$typeConfigs = self::$navigation[$type];
|
||||||
|
if (! isset($typeConfigs[$branch]) || $fromDisk) {
|
||||||
|
$typeConfigs[$branch] = static::fromIni(static::getNavigationConfigPath($type, $username));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $typeConfigs[$branch];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the path to the configuration file for the given navigation item type and user
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @param string $username
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws IcingaException In case the given type is unknown
|
||||||
|
*/
|
||||||
|
protected static function getNavigationConfigPath($type, $username = null)
|
||||||
|
{
|
||||||
|
$itemTypeConfig = Navigation::getItemTypeConfiguration();
|
||||||
|
if (! isset($itemTypeConfig[$type])) {
|
||||||
|
throw new IcingaException('Invalid navigation item type %s provided', $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($itemTypeConfig[$type]['config'])) {
|
||||||
|
$filename = $itemTypeConfig[$type]['config'] . '.ini';
|
||||||
|
} else {
|
||||||
|
$filename = $type . 's.ini';
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::resolvePath(
|
||||||
|
($username ? 'preferences' . DIRECTORY_SEPARATOR . $username : 'navigation')
|
||||||
|
. DIRECTORY_SEPARATOR
|
||||||
|
. $filename
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return this config rendered as a INI structured string
|
* Return this config rendered as a INI structured string
|
||||||
*
|
*
|
||||||
|
@ -1014,16 +1014,21 @@ class Module
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a new type of configurable navigation item with a optional label
|
* Provide a new type of configurable navigation item with a optional label and config filename
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @param string $type
|
||||||
* @param string $label
|
* @param string $label
|
||||||
|
* @param string $config
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
protected function provideNavigationItem($type, $label = null)
|
protected function provideNavigationItem($type, $label = null, $config = null)
|
||||||
{
|
{
|
||||||
$this->navigationItems[$type] = $label ?: $type;
|
$this->navigationItems[$type] = array(
|
||||||
|
'label' => $label,
|
||||||
|
'config' => $config
|
||||||
|
);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,33 +8,41 @@ namespace Icinga\Application;
|
|||||||
*/
|
*/
|
||||||
class Version
|
class Version
|
||||||
{
|
{
|
||||||
|
const VERSION = '2.0.0-rc1';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the version of this instance of Icinga Web 2
|
* Get the version of this instance of Icinga Web 2
|
||||||
*
|
*
|
||||||
* @return array|false array on success, false otherwise
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function get()
|
public static function get()
|
||||||
{
|
{
|
||||||
if (false === ($appVersion = @file_get_contents(
|
$version = array('appVersion' => self::VERSION);
|
||||||
Icinga::app()->getApplicationDir() . DIRECTORY_SEPARATOR . 'VERSION'
|
if (false !== ($appVersion = @file_get_contents(Icinga::app()->getApplicationDir('VERSION')))) {
|
||||||
))) {
|
$matches = array();
|
||||||
return false;
|
if (@preg_match('/^(?P<gitCommitID>\w+) (?P<gitCommitDate>\S+)/', $appVersion, $matches)) {
|
||||||
}
|
return array_merge($version, $matches);
|
||||||
|
|
||||||
$matches = array();
|
|
||||||
if (false === ($res = preg_match(
|
|
||||||
'/(?<!.)\s*(?P<gitCommitID>\w+)(?:\s*\(.*?(?:(?<=[\(,])\s*tag\s*:\s*v(?P<appVersion>.+?)\s*(?=[\),]).*?)?\))?\s*(?P<gitCommitDate>\S+)/ms',
|
|
||||||
$appVersion,
|
|
||||||
$matches
|
|
||||||
)) || $res === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($matches as $key => $value) {
|
|
||||||
if (is_int($key) || $value === '') {
|
|
||||||
unset($matches[$key]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $matches;
|
|
||||||
|
$gitDir = Icinga::app()->getBaseDir('.git');
|
||||||
|
$gitHead = @file_get_contents($gitDir . DIRECTORY_SEPARATOR . 'HEAD');
|
||||||
|
if (false !== $gitHead) {
|
||||||
|
$matches = array();
|
||||||
|
if (@preg_match('/(?<!.)ref:\s+(.+?)$/ms', $gitHead, $matches)) {
|
||||||
|
$gitCommitID = @file_get_contents($gitDir . DIRECTORY_SEPARATOR . $matches[1]);
|
||||||
|
} else {
|
||||||
|
$gitCommitID = $gitHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== $gitCommitID) {
|
||||||
|
$matches = array();
|
||||||
|
if (@preg_match('/(?<!.)(?P<gitCommitID>[0-9a-f]+)$/ms', $gitCommitID, $matches)) {
|
||||||
|
return array_merge($version, $matches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,12 +179,11 @@ class Web extends EmbeddedWeb
|
|||||||
*/
|
*/
|
||||||
public function getSharedNavigation($type)
|
public function getSharedNavigation($type)
|
||||||
{
|
{
|
||||||
$config = Config::app('navigation')->getConfigObject();
|
$config = Config::navigation($type === 'dashboard-pane' ? 'dashlet' : $type);
|
||||||
$config->setKeyColumn('name');
|
|
||||||
|
|
||||||
if ($type === 'dashboard-pane') {
|
if ($type === 'dashboard-pane') {
|
||||||
$panes = array();
|
$panes = array();
|
||||||
foreach ($config->select()->where('type', 'dashlet') as $dashletName => $dashletConfig) {
|
foreach ($config as $dashletName => $dashletConfig) {
|
||||||
if ($this->hasAccessToSharedNavigationItem($dashletConfig)) {
|
if ($this->hasAccessToSharedNavigationItem($dashletConfig)) {
|
||||||
// TODO: Throw ConfigurationError if pane or url is missing
|
// TODO: Throw ConfigurationError if pane or url is missing
|
||||||
$panes[$dashletConfig->pane][$dashletName] = $dashletConfig->url;
|
$panes[$dashletConfig->pane][$dashletName] = $dashletConfig->url;
|
||||||
@ -203,7 +202,7 @@ class Web extends EmbeddedWeb
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$items = array();
|
$items = array();
|
||||||
foreach ($config->select()->where('type', $type) as $name => $typeConfig) {
|
foreach ($config as $name => $typeConfig) {
|
||||||
if ($this->hasAccessToSharedNavigationItem($typeConfig)) {
|
if ($this->hasAccessToSharedNavigationItem($typeConfig)) {
|
||||||
$items[$name] = $typeConfig;
|
$items[$name] = $typeConfig;
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,16 @@ use Icinga\Protocol\Ldap\Expression;
|
|||||||
use Icinga\Repository\LdapRepository;
|
use Icinga\Repository\LdapRepository;
|
||||||
use Icinga\Repository\RepositoryQuery;
|
use Icinga\Repository\RepositoryQuery;
|
||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
use Icinga\Application\Logger;
|
|
||||||
|
|
||||||
class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBackendInterface
|
class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The user backend being associated with this user group backend
|
||||||
|
*
|
||||||
|
* @var LdapUserBackend
|
||||||
|
*/
|
||||||
|
protected $userBackend;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base DN to use for a user query
|
* The base DN to use for a user query
|
||||||
*
|
*
|
||||||
@ -105,84 +111,26 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normed attribute names based on known LDAP environments
|
* Set the user backend to be associated with this user group backend
|
||||||
*
|
*
|
||||||
* @var array
|
* @param LdapUserBackend $backend
|
||||||
*/
|
|
||||||
protected $normedAttributes = array(
|
|
||||||
'uid' => 'uid',
|
|
||||||
'gid' => 'gid',
|
|
||||||
'user' => 'user',
|
|
||||||
'group' => 'group',
|
|
||||||
'member' => 'member',
|
|
||||||
'inetorgperson' => 'inetOrgPerson',
|
|
||||||
'samaccountname' => 'sAMAccountName'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of this repository
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The datasource being used
|
|
||||||
*
|
|
||||||
* @var Connection
|
|
||||||
*/
|
|
||||||
protected $ds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new LDAP repository object
|
|
||||||
*
|
|
||||||
* @param Connection $ds The data source to use
|
|
||||||
*/
|
|
||||||
public function __construct($ds)
|
|
||||||
{
|
|
||||||
$this->ds = $ds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the given attribute name normed to known LDAP enviroments, if possible
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function getNormedAttribute($name)
|
|
||||||
{
|
|
||||||
$loweredName = strtolower($name);
|
|
||||||
if (array_key_exists($loweredName, $this->normedAttributes)) {
|
|
||||||
return $this->normedAttributes[$loweredName];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set this repository's name
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setName($name)
|
public function setUserBackend(LdapUserBackend $backend)
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->userBackend = $backend;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return this repository's name
|
* Return the user backend being associated with this user group backend
|
||||||
*
|
*
|
||||||
* In case no name has been explicitly set yet, the class name is returned.
|
* @return LdapUserBackend
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function getName()
|
public function getUserBackend()
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->userBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -453,7 +401,6 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
$lastModifiedAttribute = 'modifyTimestamp';
|
$lastModifiedAttribute = 'modifyTimestamp';
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jom): Fetching memberships does not work currently, we'll need some aggregate functionality!
|
|
||||||
$columns = array(
|
$columns = array(
|
||||||
'group' => $this->groupNameAttribute,
|
'group' => $this->groupNameAttribute,
|
||||||
'group_name' => $this->groupNameAttribute,
|
'group_name' => $this->groupNameAttribute,
|
||||||
@ -492,13 +439,37 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
if ($this->groupClass === null) {
|
if ($this->groupClass === null) {
|
||||||
throw new ProgrammingError('It is required to set the objectClass where to look for groups first');
|
throw new ProgrammingError('It is required to set the objectClass where to look for groups first');
|
||||||
}
|
}
|
||||||
|
if ($this->groupMemberAttribute === null) {
|
||||||
|
throw new ProgrammingError('It is required to set a attribute name where to find a group\'s members first');
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
$rules = array(
|
||||||
$this->groupClass => array(
|
$this->groupClass => array(
|
||||||
'created_at' => 'generalized_time',
|
'created_at' => 'generalized_time',
|
||||||
'last_modified' => 'generalized_time'
|
'last_modified' => 'generalized_time'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
if (! $this->isAmbiguous($this->groupClass, $this->groupMemberAttribute)) {
|
||||||
|
$rules[$this->groupClass][] = 'user_name';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the uid for the given distinguished name
|
||||||
|
*
|
||||||
|
* @param string $username
|
||||||
|
*
|
||||||
|
* @param string
|
||||||
|
*/
|
||||||
|
protected function retrieveUserName($dn)
|
||||||
|
{
|
||||||
|
return $this->ds
|
||||||
|
->select()
|
||||||
|
->from('*', array($this->userNameAttribute))
|
||||||
|
->setBase($dn)
|
||||||
|
->fetchOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -524,6 +495,27 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
return $table;
|
return $table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that the given column is a valid query target and return it or the actual name if it's an alias
|
||||||
|
*
|
||||||
|
* @param string $table The table where to look for the column or alias
|
||||||
|
* @param string $name The name or alias of the column to validate
|
||||||
|
* @param RepositoryQuery $query An optional query to pass as context
|
||||||
|
*
|
||||||
|
* @return string The given column's name
|
||||||
|
*
|
||||||
|
* @throws QueryException In case the given column is not a valid query column
|
||||||
|
*/
|
||||||
|
public function requireQueryColumn($table, $name, RepositoryQuery $query = null)
|
||||||
|
{
|
||||||
|
$column = parent::requireQueryColumn($table, $name, $query);
|
||||||
|
if ($name === 'user_name' && $query !== null) {
|
||||||
|
$query->getQuery()->setUnfoldAttribute('user_name');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $column;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the groups the given user is a member of
|
* Return the groups the given user is a member of
|
||||||
*
|
*
|
||||||
@ -533,43 +525,37 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
*/
|
*/
|
||||||
public function getMemberships(User $user)
|
public function getMemberships(User $user)
|
||||||
{
|
{
|
||||||
if ($this->groupClass === 'posixGroup') {
|
if ($this->isAmbiguous($this->groupClass, $this->groupMemberAttribute)) {
|
||||||
// Posix group only uses simple user name
|
$queryValue = $user->getUsername();
|
||||||
$userDn = $user->getUsername();
|
} elseif (($queryValue = $user->getAdditional('ldap_dn')) === null) {
|
||||||
} else {
|
$userQuery = $this->ds
|
||||||
// LDAP groups use the complete DN
|
->select()
|
||||||
if (($userDn = $user->getAdditional('ldap_dn')) === null) {
|
->from($this->userClass)
|
||||||
$userQuery = $this->ds
|
->where($this->userNameAttribute, $user->getUsername())
|
||||||
->select()
|
->setBase($this->userBaseDn)
|
||||||
->from($this->userClass)
|
->setUsePagedResults(false);
|
||||||
->where($this->userNameAttribute, $user->getUsername())
|
if ($this->userFilter) {
|
||||||
->setBase($this->userBaseDn)
|
$userQuery->where(new Expression($this->userFilter));
|
||||||
->setUsePagedResults(false);
|
}
|
||||||
if ($this->userFilter) {
|
|
||||||
$userQuery->where(new Expression($this->userFilter));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($userDn = $userQuery->fetchDn()) === null) {
|
if (($queryValue = $userQuery->fetchDn()) === null) {
|
||||||
return array();
|
return array();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$groupQuery = $this->ds
|
$groupQuery = $this->ds
|
||||||
->select()
|
->select()
|
||||||
->from($this->groupClass, array($this->groupNameAttribute))
|
->from($this->groupClass, array($this->groupNameAttribute))
|
||||||
->where($this->groupMemberAttribute, $userDn)
|
->where($this->groupMemberAttribute, $queryValue)
|
||||||
->setBase($this->groupBaseDn);
|
->setBase($this->groupBaseDn);
|
||||||
if ($this->groupFilter) {
|
if ($this->groupFilter) {
|
||||||
$groupQuery->where(new Expression($this->groupFilter));
|
$groupQuery->where(new Expression($this->groupFilter));
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::debug('Fetching groups for user %s using filter %s.', $user->getUsername(), $groupQuery->__toString());
|
|
||||||
$groups = array();
|
$groups = array();
|
||||||
foreach ($groupQuery as $row) {
|
foreach ($groupQuery as $row) {
|
||||||
$groups[] = $row->{$this->groupNameAttribute};
|
$groups[] = $row->{$this->groupNameAttribute};
|
||||||
}
|
}
|
||||||
Logger::debug('Fetched %d groups: %s.', count($groups), join(', ', $groups));
|
|
||||||
|
|
||||||
return $groups;
|
return $groups;
|
||||||
}
|
}
|
||||||
@ -610,6 +596,7 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->setUserBackend($userBackend);
|
||||||
$defaults->merge(array(
|
$defaults->merge(array(
|
||||||
'user_base_dn' => $userBackend->getBaseDn(),
|
'user_base_dn' => $userBackend->getBaseDn(),
|
||||||
'user_class' => $userBackend->getUserClass(),
|
'user_class' => $userBackend->getUserClass(),
|
||||||
@ -661,4 +648,4 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
'group_member_attribute' => 'member'
|
'group_member_attribute' => 'member'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -80,7 +80,7 @@ class ArrayDatasource implements Selectable
|
|||||||
*/
|
*/
|
||||||
public function select()
|
public function select()
|
||||||
{
|
{
|
||||||
return new SimpleQuery($this);
|
return new SimpleQuery(clone $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -358,9 +358,25 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
*/
|
*/
|
||||||
public function count(LdapQuery $query)
|
public function count(LdapQuery $query)
|
||||||
{
|
{
|
||||||
$ds = $this->getConnection();
|
|
||||||
$this->bind();
|
$this->bind();
|
||||||
|
|
||||||
|
if (($unfoldAttribute = $query->getUnfoldAttribute()) !== null) {
|
||||||
|
$desiredColumns = $query->getColumns();
|
||||||
|
if (isset($desiredColumns[$unfoldAttribute])) {
|
||||||
|
$fields = array($unfoldAttribute => $desiredColumns[$unfoldAttribute]);
|
||||||
|
} elseif (in_array($unfoldAttribute, $desiredColumns, true)) {
|
||||||
|
$fields = array($unfoldAttribute);
|
||||||
|
} else {
|
||||||
|
throw new ProgrammingError(
|
||||||
|
'The attribute used to unfold a query\'s result must be selected'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = $this->runQuery($query, $fields);
|
||||||
|
return count($res);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ds = $this->getConnection();
|
||||||
$results = @ldap_search(
|
$results = @ldap_search(
|
||||||
$ds,
|
$ds,
|
||||||
$query->getBase() ?: $this->getDn(),
|
$query->getBase() ?: $this->getDn(),
|
||||||
@ -658,7 +674,7 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
protected function runQuery(LdapQuery $query, array $fields = null)
|
protected function runQuery(LdapQuery $query, array $fields = null)
|
||||||
{
|
{
|
||||||
$limit = $query->getLimit();
|
$limit = $query->getLimit();
|
||||||
$offset = $query->hasOffset() ? $query->getOffset() - 1 : 0;
|
$offset = $query->hasOffset() ? $query->getOffset() : 0;
|
||||||
|
|
||||||
if ($fields === null) {
|
if ($fields === null) {
|
||||||
$fields = $query->getColumns();
|
$fields = $query->getColumns();
|
||||||
@ -711,13 +727,41 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
$count = 0;
|
$count = 0;
|
||||||
$entries = array();
|
$entries = array();
|
||||||
$entry = ldap_first_entry($ds, $results);
|
$entry = ldap_first_entry($ds, $results);
|
||||||
|
$unfoldAttribute = $query->getUnfoldAttribute();
|
||||||
do {
|
do {
|
||||||
$count += 1;
|
if ($unfoldAttribute) {
|
||||||
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
$rows = $this->cleanupAttributes(
|
||||||
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
|
|
||||||
ldap_get_attributes($ds, $entry),
|
ldap_get_attributes($ds, $entry),
|
||||||
array_flip($fields)
|
array_flip($fields),
|
||||||
|
$unfoldAttribute
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (is_array($rows)) {
|
||||||
|
// TODO: Register the DN the same way as a section name in the ArrayDatasource!
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($serverSorting && $limit > 0 && $limit === count($entries)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[ldap_get_dn($ds, $entry)] = $rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
|
||||||
|
ldap_get_attributes($ds, $entry),
|
||||||
|
array_flip($fields)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while ((! $serverSorting || $limit === 0 || $limit !== count($entries))
|
} while ((! $serverSorting || $limit === 0 || $limit !== count($entries))
|
||||||
&& ($entry = ldap_next_entry($ds, $entry))
|
&& ($entry = ldap_next_entry($ds, $entry))
|
||||||
@ -754,7 +798,7 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
}
|
}
|
||||||
|
|
||||||
$limit = $query->getLimit();
|
$limit = $query->getLimit();
|
||||||
$offset = $query->hasOffset() ? $query->getOffset() - 1 : 0;
|
$offset = $query->hasOffset() ? $query->getOffset() : 0;
|
||||||
$queryString = (string) $query;
|
$queryString = (string) $query;
|
||||||
$base = $query->getBase() ?: $this->rootDn;
|
$base = $query->getBase() ?: $this->rootDn;
|
||||||
|
|
||||||
@ -776,6 +820,7 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
$count = 0;
|
$count = 0;
|
||||||
$cookie = '';
|
$cookie = '';
|
||||||
$entries = array();
|
$entries = array();
|
||||||
|
$unfoldAttribute = $query->getUnfoldAttribute();
|
||||||
do {
|
do {
|
||||||
// Do not request the pagination control as a critical extension, as we want the
|
// Do not request the pagination control as a critical extension, as we want the
|
||||||
// server to return results even if the paged search request cannot be satisfied
|
// server to return results even if the paged search request cannot be satisfied
|
||||||
@ -826,12 +871,39 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
|
|
||||||
$entry = ldap_first_entry($ds, $results);
|
$entry = ldap_first_entry($ds, $results);
|
||||||
do {
|
do {
|
||||||
$count += 1;
|
if ($unfoldAttribute) {
|
||||||
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
$rows = $this->cleanupAttributes(
|
||||||
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
|
|
||||||
ldap_get_attributes($ds, $entry),
|
ldap_get_attributes($ds, $entry),
|
||||||
array_flip($fields)
|
array_flip($fields),
|
||||||
|
$unfoldAttribute
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (is_array($rows)) {
|
||||||
|
// TODO: Register the DN the same way as a section name in the ArrayDatasource!
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($serverSorting && $limit > 0 && $limit === count($entries)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[ldap_get_dn($ds, $entry)] = $rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
|
||||||
|
ldap_get_attributes($ds, $entry),
|
||||||
|
array_flip($fields)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (
|
} while (
|
||||||
(! $serverSorting || $limit === 0 || $limit !== count($entries))
|
(! $serverSorting || $limit === 0 || $limit !== count($entries))
|
||||||
@ -861,9 +933,6 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
// the server: https://www.ietf.org/rfc/rfc2696.txt
|
// the server: https://www.ietf.org/rfc/rfc2696.txt
|
||||||
ldap_control_paged_result($ds, 0, false, $cookie);
|
ldap_control_paged_result($ds, 0, false, $cookie);
|
||||||
ldap_search($ds, $base, $queryString); // Returns no entries, due to the page size
|
ldap_search($ds, $base, $queryString); // Returns no entries, due to the page size
|
||||||
} else {
|
|
||||||
// Reset the paged search request so that subsequent requests succeed
|
|
||||||
ldap_control_paged_result($ds, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $serverSorting && $query->hasOrder()) {
|
if (! $serverSorting && $query->hasOrder()) {
|
||||||
@ -879,14 +948,16 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
/**
|
/**
|
||||||
* Clean up the given attributes and return them as simple object
|
* Clean up the given attributes and return them as simple object
|
||||||
*
|
*
|
||||||
* Applies column aliases, aggregates multi-value attributes as array and sets null for each missing attribute.
|
* Applies column aliases, aggregates/unfolds multi-value attributes
|
||||||
|
* as array and sets null for each missing attribute.
|
||||||
*
|
*
|
||||||
* @param array $attributes
|
* @param array $attributes
|
||||||
* @param array $requestedFields
|
* @param array $requestedFields
|
||||||
|
* @param string $unfoldAttribute
|
||||||
*
|
*
|
||||||
* @return object
|
* @return object|array An array in case the object has been unfolded
|
||||||
*/
|
*/
|
||||||
public function cleanupAttributes($attributes, array $requestedFields)
|
public function cleanupAttributes($attributes, array $requestedFields, $unfoldAttribute = null)
|
||||||
{
|
{
|
||||||
// In case the result contains attributes with a differing case than the requested fields, it is
|
// In case the result contains attributes with a differing case than the requested fields, it is
|
||||||
// necessary to create another array to map attributes case insensitively to their requested counterparts.
|
// necessary to create another array to map attributes case insensitively to their requested counterparts.
|
||||||
@ -927,6 +998,24 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
$unfoldAttribute !== null
|
||||||
|
&& isset($cleanedAttributes[$unfoldAttribute])
|
||||||
|
&& is_array($cleanedAttributes[$unfoldAttribute])
|
||||||
|
) {
|
||||||
|
$values = $cleanedAttributes[$unfoldAttribute];
|
||||||
|
unset($cleanedAttributes[$unfoldAttribute]);
|
||||||
|
$baseRow = (object) $cleanedAttributes;
|
||||||
|
$rows = array();
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$row = clone $baseRow;
|
||||||
|
$row->{$unfoldAttribute} = $value;
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
|
||||||
return (object) $cleanedAttributes;
|
return (object) $cleanedAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,13 @@ class LdapQuery extends SimpleQuery
|
|||||||
*/
|
*/
|
||||||
protected $usePagedResults;
|
protected $usePagedResults;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the attribute used to unfold the result
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $unfoldAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize this query
|
* Initialize this query
|
||||||
*/
|
*/
|
||||||
@ -90,6 +97,29 @@ class LdapQuery extends SimpleQuery
|
|||||||
return $this->usePagedResults;
|
return $this->usePagedResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the attribute to be used to unfold the result
|
||||||
|
*
|
||||||
|
* @param string $attributeName
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setUnfoldAttribute($attributeName)
|
||||||
|
{
|
||||||
|
$this->unfoldAttribute = $attributeName;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the attribute to use to unfold the result
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUnfoldAttribute()
|
||||||
|
{
|
||||||
|
return $this->unfoldAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose an objectClass and the columns you are interested in
|
* Choose an objectClass and the columns you are interested in
|
||||||
*
|
*
|
||||||
|
@ -28,13 +28,27 @@ abstract class LdapRepository extends Repository
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $normedAttributes = array(
|
protected $normedAttributes = array(
|
||||||
'uid' => 'uid',
|
'uid' => 'uid',
|
||||||
'gid' => 'gid',
|
'gid' => 'gid',
|
||||||
'user' => 'user',
|
'user' => 'user',
|
||||||
'group' => 'group',
|
'group' => 'group',
|
||||||
'member' => 'member',
|
'member' => 'member',
|
||||||
'inetorgperson' => 'inetOrgPerson',
|
'memberuid' => 'memberUid',
|
||||||
'samaccountname' => 'sAMAccountName'
|
'posixgroup' => 'posixGroup',
|
||||||
|
'uniquemember' => 'uniqueMember',
|
||||||
|
'groupofnames' => 'groupOfNames',
|
||||||
|
'inetorgperson' => 'inetOrgPerson',
|
||||||
|
'samaccountname' => 'sAMAccountName',
|
||||||
|
'groupofuniquenames' => 'groupOfUniqueNames'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object attributes whose value is not distinguished name
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $ambiguousAttributes = array(
|
||||||
|
'posixGroup' => 'memberUid'
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,4 +77,17 @@ abstract class LdapRepository extends Repository
|
|||||||
|
|
||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Return whether the given object attribute's value is not a distinguished name
|
||||||
|
*
|
||||||
|
* @param string $objectClass
|
||||||
|
* @param string $attributeName
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isAmbiguous($objectClass, $attributeName)
|
||||||
|
{
|
||||||
|
return isset($this->ambiguousAttributes[$objectClass][$attributeName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -479,22 +479,6 @@ class User
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load and return this user's navigation configuration
|
|
||||||
*
|
|
||||||
* @return Config
|
|
||||||
*/
|
|
||||||
public function loadNavigationConfig()
|
|
||||||
{
|
|
||||||
return Config::fromIni(
|
|
||||||
Config::resolvePath('preferences')
|
|
||||||
. DIRECTORY_SEPARATOR
|
|
||||||
. $this->getUsername()
|
|
||||||
. DIRECTORY_SEPARATOR
|
|
||||||
. 'navigation.ini'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load and return this user's configured navigation of the given type
|
* Load and return this user's configured navigation of the given type
|
||||||
*
|
*
|
||||||
@ -504,12 +488,11 @@ class User
|
|||||||
*/
|
*/
|
||||||
public function getNavigation($type)
|
public function getNavigation($type)
|
||||||
{
|
{
|
||||||
$config = $this->loadNavigationConfig();
|
$config = Config::navigation($type === 'dashboard-pane' ? 'dashlet' : $type, $this->getUsername());
|
||||||
$config->getConfigObject()->setKeyColumn('name');
|
|
||||||
|
|
||||||
if ($type === 'dashboard-pane') {
|
if ($type === 'dashboard-pane') {
|
||||||
$panes = array();
|
$panes = array();
|
||||||
foreach ($config->select()->where('type', 'dashlet') as $dashletName => $dashletConfig) {
|
foreach ($config as $dashletName => $dashletConfig) {
|
||||||
// TODO: Throw ConfigurationError if pane or url is missing
|
// TODO: Throw ConfigurationError if pane or url is missing
|
||||||
$panes[$dashletConfig->pane][$dashletName] = $dashletConfig->url;
|
$panes[$dashletConfig->pane][$dashletName] = $dashletConfig->url;
|
||||||
}
|
}
|
||||||
@ -525,7 +508,7 @@ class User
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$navigation = Navigation::fromConfig($config->select()->where('type', $type));
|
$navigation = Navigation::fromConfig($config);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $navigation;
|
return $navigation;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
namespace Icinga\Web;
|
namespace Icinga\Web;
|
||||||
|
|
||||||
class FileCache
|
class FileCache
|
||||||
@ -191,7 +192,7 @@ class FileCache
|
|||||||
* Whether the given ETag matchesspecific file(s) on disk
|
* Whether the given ETag matchesspecific file(s) on disk
|
||||||
*
|
*
|
||||||
* If no ETag is given we'll try to fetch the one from the current
|
* If no ETag is given we'll try to fetch the one from the current
|
||||||
* HTTP request.
|
* HTTP request. Respects HTTP Cache-Control: no-cache, if set.
|
||||||
*
|
*
|
||||||
* @param string|array $files file(s) to check
|
* @param string|array $files file(s) to check
|
||||||
* @param string $match ETag to match against
|
* @param string $match ETag to match against
|
||||||
@ -208,6 +209,9 @@ class FileCache
|
|||||||
if (! $match) {
|
if (! $match) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isset($_SERVER['HTTP_CACHE_CONTROL']) && $_SERVER['HTTP_CACHE_CONTROL'] === 'no-cache') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$etag = self::etagForFiles($files);
|
$etag = self::etagForFiles($files);
|
||||||
return $match === $etag ? $etag : false;
|
return $match === $etag ? $etag : false;
|
||||||
|
@ -27,7 +27,8 @@ class JavaScript
|
|||||||
'js/icinga/behavior/tristate.js',
|
'js/icinga/behavior/tristate.js',
|
||||||
'js/icinga/behavior/navigation.js',
|
'js/icinga/behavior/navigation.js',
|
||||||
'js/icinga/behavior/form.js',
|
'js/icinga/behavior/form.js',
|
||||||
'js/icinga/behavior/actiontable.js'
|
'js/icinga/behavior/actiontable.js',
|
||||||
|
'js/icinga/behavior/selectable.js'
|
||||||
);
|
);
|
||||||
|
|
||||||
protected static $vendorFiles = array(
|
protected static $vendorFiles = array(
|
||||||
|
@ -429,12 +429,14 @@ class Navigation implements ArrayAccess, Countable, IteratorAggregate
|
|||||||
*/
|
*/
|
||||||
public function load($type)
|
public function load($type)
|
||||||
{
|
{
|
||||||
// Shareables
|
|
||||||
$this->merge(Icinga::app()->getSharedNavigation($type));
|
|
||||||
|
|
||||||
// User Preferences
|
|
||||||
$user = Auth::getInstance()->getUser();
|
$user = Auth::getInstance()->getUser();
|
||||||
$this->merge($user->getNavigation($type));
|
if ($type !== 'dashboard-pane') {
|
||||||
|
// Shareables
|
||||||
|
$this->merge(Icinga::app()->getSharedNavigation($type));
|
||||||
|
|
||||||
|
// User Preferences
|
||||||
|
$this->merge($user->getNavigation($type));
|
||||||
|
}
|
||||||
|
|
||||||
// Modules
|
// Modules
|
||||||
$moduleManager = Icinga::app()->getModuleManager();
|
$moduleManager = Icinga::app()->getModuleManager();
|
||||||
@ -451,6 +453,39 @@ class Navigation implements ArrayAccess, Countable, IteratorAggregate
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the global navigation item type configuration
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getItemTypeConfiguration()
|
||||||
|
{
|
||||||
|
$defaultItemTypes = array(
|
||||||
|
'menu-item' => array(
|
||||||
|
'label' => t('Menu Entry'),
|
||||||
|
'config' => 'menu'
|
||||||
|
)/*, // Disabled, until it is able to fully replace the old implementation
|
||||||
|
'dashlet' => array(
|
||||||
|
'label' => 'Dashlet',
|
||||||
|
'config' => 'dashboard'
|
||||||
|
)*/
|
||||||
|
);
|
||||||
|
|
||||||
|
$moduleItemTypes = array();
|
||||||
|
$moduleManager = Icinga::app()->getModuleManager();
|
||||||
|
foreach ($moduleManager->getLoadedModules() as $module) {
|
||||||
|
if (Auth::getInstance()->hasPermission($moduleManager::MODULE_PERMISSION_NS . $module->getName())) {
|
||||||
|
foreach ($module->getNavigationItems() as $type => $options) {
|
||||||
|
if (! isset($moduleItemTypes[$type])) {
|
||||||
|
$moduleItemTypes[$type] = $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge($defaultItemTypes, $moduleItemTypes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and return a new set of navigation items for the given configuration
|
* Create and return a new set of navigation items for the given configuration
|
||||||
*
|
*
|
||||||
|
@ -36,6 +36,13 @@ class NavigationItemRenderer
|
|||||||
*/
|
*/
|
||||||
protected $internalLinkTargets;
|
protected $internalLinkTargets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to escape the label
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $escapeLabel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new NavigationItemRenderer
|
* Create a new NavigationItemRenderer
|
||||||
*
|
*
|
||||||
@ -126,6 +133,29 @@ class NavigationItemRenderer
|
|||||||
return $this->item;
|
return $this->item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether to escape the label
|
||||||
|
*
|
||||||
|
* @param bool $state
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setEscapeLabel($state = true)
|
||||||
|
{
|
||||||
|
$this->escapeLabel = (bool) $state;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether to escape the label
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getEscapeLabel()
|
||||||
|
{
|
||||||
|
return $this->escapeLabel !== null ? $this->escapeLabel : true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the given navigation item as HTML anchor
|
* Render the given navigation item as HTML anchor
|
||||||
*
|
*
|
||||||
@ -144,7 +174,9 @@ class NavigationItemRenderer
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$label = $this->view()->escape($item->getLabel());
|
$label = $this->getEscapeLabel()
|
||||||
|
? $this->view()->escape($item->getLabel())
|
||||||
|
: $item->getLabel();
|
||||||
if (($icon = $item->getIcon()) !== null) {
|
if (($icon = $item->getIcon()) !== null) {
|
||||||
$label = $this->view()->icon($icon) . $label;
|
$label = $this->view()->icon($icon) . $label;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,9 @@ class StyleSheet
|
|||||||
'css/icinga/selection-toolbar.less',
|
'css/icinga/selection-toolbar.less',
|
||||||
'css/icinga/login.less',
|
'css/icinga/login.less',
|
||||||
'css/icinga/controls.less',
|
'css/icinga/controls.less',
|
||||||
'css/icinga/dev.less'
|
'css/icinga/dev.less',
|
||||||
|
'css/icinga/logo.less',
|
||||||
|
'css/icinga/about.less'
|
||||||
);
|
);
|
||||||
|
|
||||||
public static function compileForPdf()
|
public static function compileForPdf()
|
||||||
|
@ -75,7 +75,7 @@ class Url
|
|||||||
}
|
}
|
||||||
|
|
||||||
$url = new Url();
|
$url = new Url();
|
||||||
$url->setPath($request->getPathInfo());
|
$url->setPath(ltrim($request->getPathInfo(), '/'));
|
||||||
|
|
||||||
// $urlParams = UrlParams::fromQueryString($request->getQuery());
|
// $urlParams = UrlParams::fromQueryString($request->getQuery());
|
||||||
if (isset($_SERVER['QUERY_STRING'])) {
|
if (isset($_SERVER['QUERY_STRING'])) {
|
||||||
@ -159,16 +159,17 @@ class Url
|
|||||||
if (isset($urlParts['path'])) {
|
if (isset($urlParts['path'])) {
|
||||||
$urlPath = $urlParts['path'];
|
$urlPath = $urlParts['path'];
|
||||||
if ($urlPath && $urlPath[0] === '/') {
|
if ($urlPath && $urlPath[0] === '/') {
|
||||||
$baseUrl = '';
|
if ($baseUrl) {
|
||||||
|
$urlPath = substr($urlPath, 1);
|
||||||
|
} elseif (strpos($urlPath, $request->getBaseUrl()) === 0) {
|
||||||
|
$baseUrl = $request->getBaseUrl();
|
||||||
|
$urlPath = substr($urlPath, strlen($baseUrl) + 1);
|
||||||
|
}
|
||||||
} elseif (! $baseUrl) {
|
} elseif (! $baseUrl) {
|
||||||
$baseUrl = $request->getBaseUrl();
|
$baseUrl = $request->getBaseUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($baseUrl && !$urlObject->isExternal() && strpos($urlPath, $baseUrl) === 0) {
|
$urlObject->setPath($urlPath);
|
||||||
$urlObject->setPath(substr($urlPath, strlen($baseUrl)));
|
|
||||||
} else {
|
|
||||||
$urlObject->setPath($urlPath);
|
|
||||||
}
|
|
||||||
} elseif (! $baseUrl) {
|
} elseif (! $baseUrl) {
|
||||||
$baseUrl = $request->getBaseUrl();
|
$baseUrl = $request->getBaseUrl();
|
||||||
}
|
}
|
||||||
@ -255,7 +256,7 @@ class Url
|
|||||||
*/
|
*/
|
||||||
public function setPath($path)
|
public function setPath($path)
|
||||||
{
|
{
|
||||||
$this->path = ltrim($path, '/');
|
$this->path = $path;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,11 @@ $this->addHelperFunction('qlink', function ($title, $url, $params = null, $prope
|
|||||||
$icon = $view->icon($properties['icon']);
|
$icon = $view->icon($properties['icon']);
|
||||||
unset($properties['icon']);
|
unset($properties['icon']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('img', $properties)) {
|
||||||
|
$icon = $view->img($properties['img']);
|
||||||
|
unset($properties['img']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sprintf(
|
return sprintf(
|
||||||
|
@ -85,6 +85,7 @@ class Dashboard extends AbstractWidget
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->mergePanes($panes);
|
$this->mergePanes($panes);
|
||||||
|
$this->loadUserDashboards();
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
library/Icinga/Web/Widget/Tabextension/MenuAction.php
Normal file
35
library/Icinga/Web/Widget/Tabextension/MenuAction.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Web\Widget\Tabextension;
|
||||||
|
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Widget\Tabs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tabextension that allows to add the current URL as menu entry
|
||||||
|
*
|
||||||
|
* Displayed as a dropdown field in the tabs
|
||||||
|
*/
|
||||||
|
class MenuAction implements Tabextension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Applies the menu actions to the provided tabset
|
||||||
|
*
|
||||||
|
* @param Tabs $tabs The tabs object to extend with
|
||||||
|
*/
|
||||||
|
public function apply(Tabs $tabs)
|
||||||
|
{
|
||||||
|
$tabs->addAsDropdown(
|
||||||
|
'menu-entry',
|
||||||
|
array(
|
||||||
|
'icon' => 'menu',
|
||||||
|
'label' => t('Add To Menu'),
|
||||||
|
'url' => Url::fromPath('navigation/add'),
|
||||||
|
'urlParams' => array(
|
||||||
|
'url' => rawurlencode(Url::fromRequest()->getRelativeUrl())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ use Icinga\Module\Monitoring\Controller;
|
|||||||
use Icinga\Module\Monitoring\Web\Widget\SelectBox;
|
use Icinga\Module\Monitoring\Web\Widget\SelectBox;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
class AlertsummaryController extends Controller
|
class AlertsummaryController extends Controller
|
||||||
{
|
{
|
||||||
@ -53,7 +54,7 @@ class AlertsummaryController extends Controller
|
|||||||
'label' => $this->translate('Alert Summary'),
|
'label' => $this->translate('Alert Summary'),
|
||||||
'url' => Url::fromRequest()
|
'url' => Url::fromRequest()
|
||||||
)
|
)
|
||||||
)->extend(new DashboardAction())->activate('alertsummary');
|
)->extend(new DashboardAction())->extend(new MenuAction())->activate('alertsummary');
|
||||||
$this->view->title = $this->translate('Alert Summary');
|
$this->view->title = $this->translate('Alert Summary');
|
||||||
|
|
||||||
$this->view->intervalBox = $this->createIntervalBox();
|
$this->view->intervalBox = $this->createIntervalBox();
|
||||||
|
@ -7,6 +7,7 @@ use Icinga\Module\Monitoring\Controller;
|
|||||||
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm;
|
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display detailed information about a comment
|
* Display detailed information about a comment
|
||||||
@ -55,7 +56,7 @@ class CommentController extends Controller
|
|||||||
'title' => $this->translate('Display detailed information about a comment.'),
|
'title' => $this->translate('Display detailed information about a comment.'),
|
||||||
'url' =>'monitoring/comments/show'
|
'url' =>'monitoring/comments/show'
|
||||||
)
|
)
|
||||||
)->activate('comment')->extend(new DashboardAction());
|
)->activate('comment')->extend(new DashboardAction())->extend(new MenuAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,6 +9,7 @@ use Icinga\Module\Monitoring\Object\Host;
|
|||||||
use Icinga\Module\Monitoring\Object\Service;
|
use Icinga\Module\Monitoring\Object\Service;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display detailed information about a downtime
|
* Display detailed information about a downtime
|
||||||
@ -65,7 +66,7 @@ class DowntimeController extends Controller
|
|||||||
'title' => $this->translate('Display detailed information about a downtime.'),
|
'title' => $this->translate('Display detailed information about a downtime.'),
|
||||||
'url' =>'monitoring/downtimes/show'
|
'url' =>'monitoring/downtimes/show'
|
||||||
)
|
)
|
||||||
)->activate('downtime')->extend(new DashboardAction());
|
)->activate('downtime')->extend(new DashboardAction())->extend(new MenuAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,6 +7,7 @@ use Icinga\Module\Monitoring\Controller;
|
|||||||
use Icinga\Module\Monitoring\Forms\Command\Instance\DisableNotificationsExpireCommandForm;
|
use Icinga\Module\Monitoring\Forms\Command\Instance\DisableNotificationsExpireCommandForm;
|
||||||
use Icinga\Module\Monitoring\Forms\Command\Instance\ToggleInstanceFeaturesCommandForm;
|
use Icinga\Module\Monitoring\Forms\Command\Instance\ToggleInstanceFeaturesCommandForm;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display process and performance information of the monitoring host and program-wide commands
|
* Display process and performance information of the monitoring host and program-wide commands
|
||||||
@ -43,7 +44,7 @@ class HealthController extends Controller
|
|||||||
'url' =>'monitoring/health/stats'
|
'url' =>'monitoring/health/stats'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
->extend(new DashboardAction());
|
->extend(new DashboardAction())->extend(new MenuAction());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,6 +77,7 @@ class HostController extends MonitoredObjectController
|
|||||||
'host_state_type',
|
'host_state_type',
|
||||||
'host_last_state_change',
|
'host_last_state_change',
|
||||||
'host_address',
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
'host_handled',
|
'host_handled',
|
||||||
'service_description',
|
'service_description',
|
||||||
'service_display_name',
|
'service_display_name',
|
||||||
|
@ -18,6 +18,7 @@ use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandF
|
|||||||
use Icinga\Module\Monitoring\Object\HostList;
|
use Icinga\Module\Monitoring\Object\HostList;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
class HostsController extends Controller
|
class HostsController extends Controller
|
||||||
{
|
{
|
||||||
@ -44,7 +45,7 @@ class HostsController extends Controller
|
|||||||
'url' => Url::fromRequest(),
|
'url' => Url::fromRequest(),
|
||||||
'icon' => 'host'
|
'icon' => 'host'
|
||||||
)
|
)
|
||||||
)->extend(new DashboardAction())->activate('show');
|
)->extend(new DashboardAction())->extend(new MenuAction())->activate('show');
|
||||||
$this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/hosts');
|
$this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/hosts');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ class HostsController extends Controller
|
|||||||
'host_icon_image_alt',
|
'host_icon_image_alt',
|
||||||
'host_name',
|
'host_name',
|
||||||
'host_address',
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
'host_state',
|
'host_state',
|
||||||
'host_problem',
|
'host_problem',
|
||||||
'host_handled',
|
'host_handled',
|
||||||
@ -92,6 +94,7 @@ class HostsController extends Controller
|
|||||||
'host_icon_image_alt',
|
'host_icon_image_alt',
|
||||||
'host_name',
|
'host_name',
|
||||||
'host_address',
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
'host_state',
|
'host_state',
|
||||||
'host_problem',
|
'host_problem',
|
||||||
'host_handled',
|
'host_handled',
|
||||||
|
@ -13,6 +13,7 @@ use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimeCommandForm;
|
|||||||
use Icinga\Module\Monitoring\Forms\StatehistoryForm;
|
use Icinga\Module\Monitoring\Forms\StatehistoryForm;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||||
use Icinga\Web\Widget\Tabs;
|
use Icinga\Web\Widget\Tabs;
|
||||||
|
|
||||||
@ -58,7 +59,6 @@ class ListController extends Controller
|
|||||||
'host_name',
|
'host_name',
|
||||||
'host_display_name',
|
'host_display_name',
|
||||||
'host_state' => $stateColumn,
|
'host_state' => $stateColumn,
|
||||||
'host_address',
|
|
||||||
'host_acknowledged',
|
'host_acknowledged',
|
||||||
'host_output',
|
'host_output',
|
||||||
'host_attempt',
|
'host_attempt',
|
||||||
@ -66,15 +66,10 @@ class ListController extends Controller
|
|||||||
'host_is_flapping',
|
'host_is_flapping',
|
||||||
'host_state_type',
|
'host_state_type',
|
||||||
'host_handled',
|
'host_handled',
|
||||||
'host_last_check',
|
|
||||||
'host_last_state_change' => $stateChangeColumn,
|
'host_last_state_change' => $stateChangeColumn,
|
||||||
'host_notifications_enabled',
|
'host_notifications_enabled',
|
||||||
'host_action_url',
|
|
||||||
'host_notes_url',
|
|
||||||
'host_active_checks_enabled',
|
'host_active_checks_enabled',
|
||||||
'host_passive_checks_enabled',
|
'host_passive_checks_enabled'
|
||||||
'host_current_check_attempt',
|
|
||||||
'host_max_check_attempts'
|
|
||||||
), $this->addColumns()));
|
), $this->addColumns()));
|
||||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||||
$this->filterQuery($query);
|
$this->filterQuery($query);
|
||||||
@ -132,10 +127,6 @@ class ListController extends Controller
|
|||||||
'host_name',
|
'host_name',
|
||||||
'host_display_name',
|
'host_display_name',
|
||||||
'host_state',
|
'host_state',
|
||||||
'host_state_type',
|
|
||||||
'host_last_state_change',
|
|
||||||
'host_address',
|
|
||||||
'host_handled',
|
|
||||||
'service_description',
|
'service_description',
|
||||||
'service_display_name',
|
'service_display_name',
|
||||||
'service_state' => $stateColumn,
|
'service_state' => $stateColumn,
|
||||||
@ -152,14 +143,9 @@ class ListController extends Controller
|
|||||||
'service_state_type',
|
'service_state_type',
|
||||||
'service_handled',
|
'service_handled',
|
||||||
'service_severity',
|
'service_severity',
|
||||||
'service_last_check',
|
|
||||||
'service_notifications_enabled',
|
'service_notifications_enabled',
|
||||||
'service_action_url',
|
|
||||||
'service_notes_url',
|
|
||||||
'service_active_checks_enabled',
|
'service_active_checks_enabled',
|
||||||
'service_passive_checks_enabled',
|
'service_passive_checks_enabled'
|
||||||
'current_check_attempt' => 'service_current_check_attempt',
|
|
||||||
'max_check_attempts' => 'service_max_check_attempts'
|
|
||||||
), $this->addColumns());
|
), $this->addColumns());
|
||||||
$query = $this->backend->select()->from('servicestatus', $columns);
|
$query = $this->backend->select()->from('servicestatus', $columns);
|
||||||
$this->applyRestriction('monitoring/filter/objects', $query);
|
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||||
@ -628,6 +614,6 @@ class ListController extends Controller
|
|||||||
*/
|
*/
|
||||||
private function createTabs()
|
private function createTabs()
|
||||||
{
|
{
|
||||||
$this->getTabs()->extend(new OutputFormat())->extend(new DashboardAction());
|
$this->getTabs()->extend(new OutputFormat())->extend(new DashboardAction())->extend(new MenuAction());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandF
|
|||||||
use Icinga\Module\Monitoring\Object\ServiceList;
|
use Icinga\Module\Monitoring\Object\ServiceList;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
class ServicesController extends Controller
|
class ServicesController extends Controller
|
||||||
{
|
{
|
||||||
@ -46,7 +47,7 @@ class ServicesController extends Controller
|
|||||||
'url' => Url::fromRequest(),
|
'url' => Url::fromRequest(),
|
||||||
'icon' => 'services'
|
'icon' => 'services'
|
||||||
)
|
)
|
||||||
)->extend(new DashboardAction())->activate('show');
|
)->extend(new DashboardAction())->extend(new MenuAction())->activate('show');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleCommandForm(ObjectsCommandForm $form)
|
protected function handleCommandForm(ObjectsCommandForm $form)
|
||||||
@ -56,6 +57,7 @@ class ServicesController extends Controller
|
|||||||
'host_icon_image_alt',
|
'host_icon_image_alt',
|
||||||
'host_name',
|
'host_name',
|
||||||
'host_address',
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
'host_output',
|
'host_output',
|
||||||
'host_state',
|
'host_state',
|
||||||
'host_problem',
|
'host_problem',
|
||||||
@ -101,6 +103,7 @@ class ServicesController extends Controller
|
|||||||
'host_icon_image_alt',
|
'host_icon_image_alt',
|
||||||
'host_name',
|
'host_name',
|
||||||
'host_address',
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
'host_output',
|
'host_output',
|
||||||
'host_state',
|
'host_state',
|
||||||
'host_problem',
|
'host_problem',
|
||||||
|
@ -6,6 +6,7 @@ namespace Icinga\Module\Monitoring\Controllers;
|
|||||||
use Icinga\Module\Monitoring\Controller;
|
use Icinga\Module\Monitoring\Controller;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
class TacticalController extends Controller
|
class TacticalController extends Controller
|
||||||
{
|
{
|
||||||
@ -22,7 +23,7 @@ class TacticalController extends Controller
|
|||||||
'label' => $this->translate('Tactical Overview'),
|
'label' => $this->translate('Tactical Overview'),
|
||||||
'url' => Url::fromRequest()
|
'url' => Url::fromRequest()
|
||||||
)
|
)
|
||||||
)->extend(new DashboardAction())->activate('tactical_overview');
|
)->extend(new DashboardAction())->extend(new MenuAction())->activate('tactical_overview');
|
||||||
$stats = $this->backend->select()->from(
|
$stats = $this->backend->select()->from(
|
||||||
'statussummary',
|
'statussummary',
|
||||||
array(
|
array(
|
||||||
|
@ -12,6 +12,7 @@ use Icinga\Module\Monitoring\Web\Widget\SelectBox;
|
|||||||
use Icinga\Util\Format;
|
use Icinga\Util\Format;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
class TimelineController extends Controller
|
class TimelineController extends Controller
|
||||||
{
|
{
|
||||||
@ -24,7 +25,7 @@ class TimelineController extends Controller
|
|||||||
'label' => $this->translate('Timeline'),
|
'label' => $this->translate('Timeline'),
|
||||||
'url' => Url::fromRequest()
|
'url' => Url::fromRequest()
|
||||||
)
|
)
|
||||||
)->extend(new DashboardAction())->activate('timeline');
|
)->extend(new DashboardAction())->extend(new MenuAction())->activate('timeline');
|
||||||
$this->view->title = $this->translate('Timeline');
|
$this->view->title = $this->translate('Timeline');
|
||||||
|
|
||||||
// TODO: filter for hard_states (precedence adjustments necessary!)
|
// TODO: filter for hard_states (precedence adjustments necessary!)
|
||||||
|
@ -16,7 +16,11 @@ foreach ($object->getActionUrls() as $i => $link) {
|
|||||||
'Action ' . ($i + 1) . $newTabInfo,
|
'Action ' . ($i + 1) . $newTabInfo,
|
||||||
array(
|
array(
|
||||||
'url' => $link,
|
'url' => $link,
|
||||||
'target' => '_blank'
|
'target' => '_blank',
|
||||||
|
'renderer' => array(
|
||||||
|
'NavigationItemRenderer',
|
||||||
|
'escape_label' => false
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php foreach ($object->customvars as $name => $value): ?>
|
<?php foreach ($object->customvars as $name => $value): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<th><?= $this->escape($name) ?></th>
|
<th><?= $this->escape(ucwords(str_replace('_', ' ', strtolower($name)))) ?></th>
|
||||||
<td><?= $this->customvar($value) ?></td>
|
<td><?= $this->customvar($value) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use Icinga\Web\Navigation\Navigation;
|
use Icinga\Web\Navigation\Navigation;
|
||||||
|
|
||||||
$navigation = new Navigation();
|
$navigation = new Navigation();
|
||||||
$navigation->load($object->getType() . '-note');
|
//$navigation->load($object->getType() . '-note');
|
||||||
foreach ($navigation as $item) {
|
foreach ($navigation as $item) {
|
||||||
$item->setObject($object);
|
$item->setObject($object);
|
||||||
}
|
}
|
||||||
@ -26,7 +26,11 @@ if (! empty($links)) {
|
|||||||
$this->escape($link) . $newTabInfo,
|
$this->escape($link) . $newTabInfo,
|
||||||
array(
|
array(
|
||||||
'url' => $link,
|
'url' => $link,
|
||||||
'target' => '_blank'
|
'target' => '_blank',
|
||||||
|
'renderer' => array(
|
||||||
|
'NavigationItemRenderer',
|
||||||
|
'escape_label' => false
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ class HoststatusQuery extends IdoQuery
|
|||||||
'host' => 'ho.name1 COLLATE latin1_general_ci',
|
'host' => 'ho.name1 COLLATE latin1_general_ci',
|
||||||
'host_action_url' => 'h.action_url',
|
'host_action_url' => 'h.action_url',
|
||||||
'host_address' => 'h.address',
|
'host_address' => 'h.address',
|
||||||
|
'host_address6' => 'h.address6',
|
||||||
'host_alias' => 'h.alias',
|
'host_alias' => 'h.alias',
|
||||||
'host_display_name' => 'h.display_name COLLATE latin1_general_ci',
|
'host_display_name' => 'h.display_name COLLATE latin1_general_ci',
|
||||||
'host_icon_image' => 'h.icon_image',
|
'host_icon_image' => 'h.icon_image',
|
||||||
|
@ -832,7 +832,7 @@ abstract class IdoQuery extends DbQuery
|
|||||||
list($type, $name) = $this->customvarNameToTypeName($customvar);
|
list($type, $name) = $this->customvarNameToTypeName($customvar);
|
||||||
$alias = ($type === 'host' ? 'hcv_' : 'scv_') . $name;
|
$alias = ($type === 'host' ? 'hcv_' : 'scv_') . $name;
|
||||||
|
|
||||||
$this->customVars[$customvar] = $alias;
|
$this->customVars[strtolower($customvar)] = $alias;
|
||||||
|
|
||||||
if ($this->hasJoinedVirtualTable('services')) {
|
if ($this->hasJoinedVirtualTable('services')) {
|
||||||
$leftcol = 's.' . $type . '_object_id';
|
$leftcol = 's.' . $type . '_object_id';
|
||||||
|
@ -27,6 +27,7 @@ class ServicestatusQuery extends IdoQuery
|
|||||||
'hosts' => array(
|
'hosts' => array(
|
||||||
'host_action_url' => 'h.action_url',
|
'host_action_url' => 'h.action_url',
|
||||||
'host_address' => 'h.address',
|
'host_address' => 'h.address',
|
||||||
|
'host_address6' => 'h.address6',
|
||||||
'host_alias' => 'h.alias COLLATE latin1_general_ci',
|
'host_alias' => 'h.alias COLLATE latin1_general_ci',
|
||||||
'host_display_name' => 'h.display_name COLLATE latin1_general_ci',
|
'host_display_name' => 'h.display_name COLLATE latin1_general_ci',
|
||||||
'host_icon_image' => 'h.icon_image',
|
'host_icon_image' => 'h.icon_image',
|
||||||
|
@ -82,7 +82,7 @@ class Controller extends IcingaWebController
|
|||||||
'service_description',
|
'service_description',
|
||||||
'servicegroup_name',
|
'servicegroup_name',
|
||||||
function ($c) {
|
function ($c) {
|
||||||
return preg_match('/^_(?:host|service)_/', $c);
|
return preg_match('/^_(?:host|service)_/i', $c);
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
foreach ($this->getRestrictions($name) as $filter) {
|
foreach ($this->getRestrictions($name) as $filter) {
|
||||||
|
@ -185,7 +185,11 @@ abstract class DataView implements QueryInterface, SortRules, FilterColumns, Ite
|
|||||||
*/
|
*/
|
||||||
public function isValidFilterTarget($column)
|
public function isValidFilterTarget($column)
|
||||||
{
|
{
|
||||||
return in_array($column, $this->getFilterColumns());
|
// Customvar
|
||||||
|
if ($column[0] === '_' && preg_match('/^_(?:host|service)_/i', $column)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return in_array($column, $this->getColumns()) || in_array($column, $this->getStaticFilterColumns());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,6 +16,7 @@ class HostStatus extends DataView
|
|||||||
'host_display_name',
|
'host_display_name',
|
||||||
'host_alias',
|
'host_alias',
|
||||||
'host_address',
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
'host_state',
|
'host_state',
|
||||||
'host_state_type',
|
'host_state_type',
|
||||||
'host_handled',
|
'host_handled',
|
||||||
|
@ -18,6 +18,7 @@ class ServiceStatus extends DataView
|
|||||||
'host_state_type',
|
'host_state_type',
|
||||||
'host_last_state_change',
|
'host_last_state_change',
|
||||||
'host_address',
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
'host_problem',
|
'host_problem',
|
||||||
'host_handled',
|
'host_handled',
|
||||||
'service_description',
|
'service_description',
|
||||||
|
@ -95,6 +95,7 @@ class Host extends MonitoredObject
|
|||||||
'host_active_checks_enabled',
|
'host_active_checks_enabled',
|
||||||
'host_active_checks_enabled_changed',
|
'host_active_checks_enabled_changed',
|
||||||
'host_address',
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
'host_alias',
|
'host_alias',
|
||||||
'host_attempt',
|
'host_attempt',
|
||||||
'host_check_command',
|
'host_check_command',
|
||||||
|
@ -14,11 +14,13 @@ class Macro
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private static $icingaMacros = array(
|
private static $icingaMacros = array(
|
||||||
'HOSTNAME' => 'host_name',
|
'HOSTNAME' => 'host_name',
|
||||||
'HOSTADDRESS' => 'host_address',
|
'HOSTADDRESS' => 'host_address',
|
||||||
'SERVICEDESC' => 'service_description',
|
'HOSTADDRESS6' => 'host_address6',
|
||||||
'host.name' => 'host_name',
|
'SERVICEDESC' => 'service_description',
|
||||||
'host.address' => 'host_address',
|
'host.name' => 'host_name',
|
||||||
|
'host.address' => 'host_address',
|
||||||
|
'host.address6' => 'host_address6',
|
||||||
'service.description' => 'service_description'
|
'service.description' => 'service_description'
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -58,8 +60,9 @@ class Macro
|
|||||||
if (isset(self::$icingaMacros[$macro]) && isset($object->{self::$icingaMacros[$macro]})) {
|
if (isset(self::$icingaMacros[$macro]) && isset($object->{self::$icingaMacros[$macro]})) {
|
||||||
return $object->{self::$icingaMacros[$macro]};
|
return $object->{self::$icingaMacros[$macro]};
|
||||||
}
|
}
|
||||||
if (isset($object->customvars[$macro])) {
|
$customVar = strtolower($macro);
|
||||||
return $object->customvars[$macro];
|
if (isset($object->customvars[$customVar])) {
|
||||||
|
return $object->customvars[$customVar];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $macro;
|
return $macro;
|
||||||
|
@ -239,7 +239,7 @@ abstract class MonitoredObject implements Filterable
|
|||||||
|
|
||||||
foreach ($this->customvars as $name => $value) {
|
foreach ($this->customvars as $name => $value) {
|
||||||
if (! is_object($value)) {
|
if (! is_object($value)) {
|
||||||
$row->{'_' . $this->getType() . '_' . strtolower(str_replace(' ', '_', $name))} = $value;
|
$row->{'_' . $this->getType() . '_' . $name} = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,8 +477,8 @@ abstract class MonitoredObject implements Filterable
|
|||||||
$this->customvars = array();
|
$this->customvars = array();
|
||||||
|
|
||||||
$customvars = $query->getQuery()->fetchAll();
|
$customvars = $query->getQuery()->fetchAll();
|
||||||
foreach ($customvars as $name => $cv) {
|
foreach ($customvars as $cv) {
|
||||||
$name = ucwords(str_replace('_', ' ', strtolower($cv->varname)));
|
$name = strtolower($cv->varname);
|
||||||
if ($blacklistPattern && preg_match($blacklistPattern, $cv->varname)) {
|
if ($blacklistPattern && preg_match($blacklistPattern, $cv->varname)) {
|
||||||
$this->customvars[$name] = '***';
|
$this->customvars[$name] = '***';
|
||||||
} elseif ($cv->is_json) {
|
} elseif ($cv->is_json) {
|
||||||
|
@ -112,6 +112,7 @@ class Service extends MonitoredObject
|
|||||||
'host_acknowledged',
|
'host_acknowledged',
|
||||||
'host_active_checks_enabled',
|
'host_active_checks_enabled',
|
||||||
'host_address',
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
'host_alias',
|
'host_alias',
|
||||||
'host_display_name',
|
'host_display_name',
|
||||||
'host_handled',
|
'host_handled',
|
||||||
|
@ -13,6 +13,7 @@ use Icinga\Module\Monitoring\Forms\Command\Object\ToggleObjectFeaturesCommandFor
|
|||||||
use Icinga\Web\Hook;
|
use Icinga\Web\Hook;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for the host and service controller
|
* Base class for the host and service controller
|
||||||
@ -232,6 +233,6 @@ abstract class MonitoredObjectController extends Controller
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$tabs->extend(new DashboardAction());
|
$tabs->extend(new DashboardAction())->extend(new MenuAction());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,14 @@ class MacroTest extends BaseTestCase
|
|||||||
$hostMock = Mockery::mock('host');
|
$hostMock = Mockery::mock('host');
|
||||||
$hostMock->host_name = 'test';
|
$hostMock->host_name = 'test';
|
||||||
$hostMock->host_address = '1.1.1.1';
|
$hostMock->host_address = '1.1.1.1';
|
||||||
|
$hostMock->host_address6 = '::1';
|
||||||
|
|
||||||
$this->assertEquals(Macro::resolveMacros('$HOSTNAME$', $hostMock), $hostMock->host_name);
|
$this->assertEquals(Macro::resolveMacros('$HOSTNAME$', $hostMock), $hostMock->host_name);
|
||||||
$this->assertEquals(Macro::resolveMacros('$HOSTADDRESS$', $hostMock), $hostMock->host_address);
|
$this->assertEquals(Macro::resolveMacros('$HOSTADDRESS$', $hostMock), $hostMock->host_address);
|
||||||
|
$this->assertEquals(Macro::resolveMacros('$HOSTADDRESS6$', $hostMock), $hostMock->host_address6);
|
||||||
$this->assertEquals(Macro::resolveMacros('$host.name$', $hostMock), $hostMock->host_name);
|
$this->assertEquals(Macro::resolveMacros('$host.name$', $hostMock), $hostMock->host_name);
|
||||||
$this->assertEquals(Macro::resolveMacros('$host.address$', $hostMock), $hostMock->host_address);
|
$this->assertEquals(Macro::resolveMacros('$host.address$', $hostMock), $hostMock->host_address);
|
||||||
|
$this->assertEquals(Macro::resolveMacros('$host.address6$', $hostMock), $hostMock->host_address6);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testServiceMacros()
|
public function testServiceMacros()
|
||||||
@ -28,13 +31,16 @@ class MacroTest extends BaseTestCase
|
|||||||
$svcMock = Mockery::mock('service');
|
$svcMock = Mockery::mock('service');
|
||||||
$svcMock->host_name = 'test';
|
$svcMock->host_name = 'test';
|
||||||
$svcMock->host_address = '1.1.1.1';
|
$svcMock->host_address = '1.1.1.1';
|
||||||
|
$svcMock->host_address6 = '::1';
|
||||||
$svcMock->service_description = 'a service';
|
$svcMock->service_description = 'a service';
|
||||||
|
|
||||||
$this->assertEquals(Macro::resolveMacros('$HOSTNAME$', $svcMock), $svcMock->host_name);
|
$this->assertEquals(Macro::resolveMacros('$HOSTNAME$', $svcMock), $svcMock->host_name);
|
||||||
$this->assertEquals(Macro::resolveMacros('$HOSTADDRESS$', $svcMock), $svcMock->host_address);
|
$this->assertEquals(Macro::resolveMacros('$HOSTADDRESS$', $svcMock), $svcMock->host_address);
|
||||||
|
$this->assertEquals(Macro::resolveMacros('$HOSTADDRESS6$', $svcMock), $svcMock->host_address6);
|
||||||
$this->assertEquals(Macro::resolveMacros('$SERVICEDESC$', $svcMock), $svcMock->service_description);
|
$this->assertEquals(Macro::resolveMacros('$SERVICEDESC$', $svcMock), $svcMock->service_description);
|
||||||
$this->assertEquals(Macro::resolveMacros('$host.name$', $svcMock), $svcMock->host_name);
|
$this->assertEquals(Macro::resolveMacros('$host.name$', $svcMock), $svcMock->host_name);
|
||||||
$this->assertEquals(Macro::resolveMacros('$host.address$', $svcMock), $svcMock->host_address);
|
$this->assertEquals(Macro::resolveMacros('$host.address$', $svcMock), $svcMock->host_address);
|
||||||
|
$this->assertEquals(Macro::resolveMacros('$host.address6$', $svcMock), $svcMock->host_address6);
|
||||||
$this->assertEquals(Macro::resolveMacros('$service.description$', $svcMock), $svcMock->service_description);
|
$this->assertEquals(Macro::resolveMacros('$service.description$', $svcMock), $svcMock->service_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<?php if ($success): ?>
|
<?php if ($success): ?>
|
||||||
<?= $this->qlink(
|
<?= $this->qlink(
|
||||||
$this->translate('Login to Icinga Web 2'),
|
$this->translate('Login to Icinga Web 2'),
|
||||||
'authentication/login',
|
'authentication/login?renderLayout',
|
||||||
null,
|
null,
|
||||||
array(
|
array(
|
||||||
'class' => 'button-like login',
|
'class' => 'button-like login',
|
||||||
@ -30,4 +30,4 @@
|
|||||||
<pre class="log-output"><?= join("\n\n", array_map(function($a) {
|
<pre class="log-output"><?= join("\n\n", array_map(function($a) {
|
||||||
return join("\n", $a);
|
return join("\n", $a);
|
||||||
}, $report)); ?></pre>
|
}, $report)); ?></pre>
|
||||||
</div>
|
</div>
|
||||||
|
9
public/css/icinga/about.less
Normal file
9
public/css/icinga/about.less
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
div.about {
|
||||||
|
width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.about-modules {
|
||||||
|
text-align: initial;
|
||||||
|
}
|
||||||
|
}
|
@ -271,14 +271,7 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#login {
|
#login {
|
||||||
.logo .image img {
|
.below-logo label {
|
||||||
width: 70%;
|
|
||||||
}
|
|
||||||
.form {
|
|
||||||
width: 100%;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
.form label {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
47
public/css/icinga/logo.less
Normal file
47
public/css/icinga/logo.less
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
background-color: @colorPetrol;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 60%;
|
||||||
|
border-bottom: 1px solid #d9d9d9d;
|
||||||
|
text-align: center;
|
||||||
|
-webkit-box-shadow: 0 3px 7px -3px #000;
|
||||||
|
-moz-box-shadow: 0 3px 7px -3px #000;
|
||||||
|
box-shadow: 0 3px 7px -3px #000;
|
||||||
|
|
||||||
|
.image {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1em;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 375px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.below-logo {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 0.9em;
|
||||||
|
top: 45%;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layout.minimal-layout {
|
||||||
|
.logo .image img {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.below-logo {
|
||||||
|
width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
}
|
BIN
public/img/bugreport.png
Normal file
BIN
public/img/bugreport.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
public/img/docs.png
Normal file
BIN
public/img/docs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
BIN
public/img/support.png
Normal file
BIN
public/img/support.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
BIN
public/img/wiki.png
Normal file
BIN
public/img/wiki.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
36
public/js/icinga/behavior/selectable.js
Normal file
36
public/js/icinga/behavior/selectable.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
;(function(Icinga, $) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Icinga.Behaviors = Icinga.Behaviors || {};
|
||||||
|
|
||||||
|
var Selectable = function(icinga) {
|
||||||
|
Icinga.EventListener.call(this, icinga);
|
||||||
|
this.on('rendered', this.onRendered, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
$.extend(Selectable.prototype, new Icinga.EventListener(), {
|
||||||
|
onRendered: function(e) {
|
||||||
|
$('.selectable', e.target).on('dblclick', e.data.self.selectText);
|
||||||
|
},
|
||||||
|
|
||||||
|
selectText: function(e) {
|
||||||
|
var b = document.body,
|
||||||
|
r;
|
||||||
|
if (b.createTextRange) {
|
||||||
|
r = b.createTextRange();
|
||||||
|
r.moveToElementText(e.target);
|
||||||
|
r.select();
|
||||||
|
} else if (window.getSelection) {
|
||||||
|
var s = window.getSelection();
|
||||||
|
r = document.createRange();
|
||||||
|
r.selectNodeContents(e.target);
|
||||||
|
s.removeAllRanges();
|
||||||
|
s.addRange(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Icinga.Behaviors.Selectable = Selectable;
|
||||||
|
})(Icinga, jQuery);
|
Loading…
x
Reference in New Issue
Block a user