Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package icingaweb2-module-director for 
openSUSE:Factory checked in at 2021-07-13 22:37:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/icingaweb2-module-director (Old)
 and      /work/SRC/openSUSE:Factory/.icingaweb2-module-director.new.2625 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "icingaweb2-module-director"

Tue Jul 13 22:37:35 2021 rev:14 rq:906049 version:1.8.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/icingaweb2-module-director/icingaweb2-module-director.changes
    2020-12-17 17:08:28.017920945 +0100
+++ 
/work/SRC/openSUSE:Factory/.icingaweb2-module-director.new.2625/icingaweb2-module-director.changes
  2021-07-13 22:37:59.889856516 +0200
@@ -1,0 +2,27 @@
+Tue Jul 13 08:32:06 UTC 2021 - ecsos <ec...@opensuse.org>
+
+- Update to 1.8.1
+  * Fixed issues
+    - You can find issues and feature requests related to this release on our 
roadmap
+  * User Interface
+    - FIX: show Override button when all Fields belong to Field Categories 
(#2303)
+    - FIX: don't fail when showing a Host overriding multiple inherited groups 
(#2253)
+    - FIX: deal with inherited values which are invalid for a select box 
(#2288)
+    - FIX: Service Set preview inline Service Template links (#2334)
+    - FIX: show Services applied with Rules involving applied Hostgroups 
(#2313)
+    - FIX: show deactivated services as such also for read-only users (#2344)
+    - FIX: Overrides for Services belonging to Sets on root Host Templates 
(#2333)
+    - FIX: show no header tabs for search result in web 2.8+ (#2141)
+    - FIX: show and link dependencies for web 2.9+ (#2354)
+  * Icinga Configuration
+    - FIX: rare race condition, where generated config might miss some files 
(#2351)
+  * Icinga API
+    - FIX: use Icinga 2's generate-ticket API, required for v2.13.0 (#2348)
+  * Import and Sync
+    - FIX: Purge didn't remove more than 1000 services at once (#2339)
+  * Automation, User Interface
+    - FIX: error message wording on failing related (or parent) object ref 
(#2224)
+  * REST API
+    - FIX: creating scheduled downtime via api failed (#1879)
+
+-------------------------------------------------------------------

Old:
----
  icingaweb2-module-director-1.8.0.tar.gz

New:
----
  icingaweb2-module-director-1.8.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ icingaweb2-module-director.spec ++++++
--- /var/tmp/diff_new_pack.12KObj/_old  2021-07-13 22:38:00.281853359 +0200
+++ /var/tmp/diff_new_pack.12KObj/_new  2021-07-13 22:38:00.285853326 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package icingaweb2-module-director
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 # See also http://en.opensuse.org/openSUSE:Specfile_guidelines
 
 Name:           icingaweb2-module-director
-Version:        1.8.0
+Version:        1.8.1
 Release:        0
 Summary:        Config module for Icinga Web 2
 License:        GPL-2.0-or-later

++++++ icingaweb2-module-director-1.8.0.tar.gz -> 
icingaweb2-module-director-1.8.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/application/controllers/PhperrorController.php
 
new/icingaweb2-module-director-1.8.1/application/controllers/PhperrorController.php
--- 
old/icingaweb2-module-director-1.8.0/application/controllers/PhperrorController.php
 2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/application/controllers/PhperrorController.php
 2021-07-13 10:18:55.000000000 +0200
@@ -3,7 +3,8 @@
 namespace Icinga\Module\Director\Controllers;
 
 use Icinga\Application\Icinga;
-use Icinga\Application\Modules\Manager;
+use Icinga\Module\Director\Application\DependencyChecker;
+use Icinga\Module\Director\Web\Table\Dependency\DependencyInfoTable;
 use Icinga\Web\Controller;
 
 class PhperrorController extends Controller
@@ -24,39 +25,19 @@
 
     public function dependenciesAction()
     {
-        $dependencies = $this->view->dependencies = 
$this->Module()->getDependencies();
-        $modules = $this->view->modules = Icinga::app()->getModuleManager();
-        // Hint: we're duplicating some code here
-        $satisfied = true;
-        foreach ($dependencies as $module => $required) {
-            /** @var Manager $this ->modules */
-            if ($modules->hasEnabled($module)) {
-                $installed = $modules->getModule($module, false)->getVersion();
-                $installed = \ltrim($installed, 'v'); // v0.6.0 VS 0.6.0
-                if (\preg_match('/^([<>=]+)\s*v?(\d+\.\d+\.\d+)$/', $required, 
$match)) {
-                    $operator = $match[1];
-                    $vRequired = $match[2];
-                    if (\version_compare($installed, $vRequired, $operator)) {
-                        continue;
-                    }
-                }
-            }
-            $satisfied = false;
-        }
-
-        if ($satisfied) {
+        $checker = new DependencyChecker(Icinga::app());
+        if ($checker->satisfiesDependencies($this->Module())) {
             $this->redirectNow('director');
         }
-
         $this->setAutorefreshInterval(15);
-        $this->getTabs()->add('error', array(
+        $this->getTabs()->add('error', [
             'label' => $this->translate('Error'),
             'url'   => $this->getRequest()->getUrl()
-        ))->activate('error');
-        $msg = $this->translate(
+        ])->activate('error');
+        $this->view->title = $this->translate('Unsatisfied dependencies');
+        $this->view->table = (new DependencyInfoTable($checker, 
$this->Module()))->render();
+        $this->view->message = $this->translate(
             "Icinga Director depends on the following modules, please 
install/upgrade as required"
         );
-        $this->view->title = $this->translate('Unsatisfied dependencies');
-        $this->view->message = sprintf($msg, PHP_VERSION);
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/application/controllers/SelfServiceController.php
 
new/icingaweb2-module-director-1.8.1/application/controllers/SelfServiceController.php
--- 
old/icingaweb2-module-director-1.8.0/application/controllers/SelfServiceController.php
      2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/application/controllers/SelfServiceController.php
      2021-07-13 10:18:55.000000000 +0200
@@ -136,12 +136,7 @@
                 throw new NotFoundError('The host "%s" is not an agent', 
$name);
             }
 
-            $this->sendPowerShellResponse(
-                Util::getIcingaTicket(
-                    $name,
-                    $this->api()->getTicketSalt()
-                )
-            );
+            $this->sendPowerShellResponse($this->api()->getTicket($name));
         } catch (Exception $e) {
             if ($e instanceof NotFoundError) {
                 $this->sendPowerShellError($e->getMessage(), 404);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/application/forms/IcingaHostForm.php 
new/icingaweb2-module-director-1.8.1/application/forms/IcingaHostForm.php
--- old/icingaweb2-module-director-1.8.0/application/forms/IcingaHostForm.php   
2020-12-15 14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/application/forms/IcingaHostForm.php   
2021-07-13 10:18:55.000000000 +0200
@@ -230,12 +230,14 @@
                 $links->addAttributes(['class' => 'strike-links']);
                 /** @var BaseHtmlElement $link */
                 foreach ($links->getContent() as $link) {
-                    $link->addAttributes([
-                        'title' => $this->translate(
-                            'Group has been inherited, but will be overridden'
-                            . ' by locally assigned group(s)'
-                        )
-                    ]);
+                    if ($link instanceof BaseHtmlElement) {
+                        $link->addAttributes([
+                            'title' => $this->translate(
+                                'Group has been inherited, but will be 
overridden'
+                                . ' by locally assigned group(s)'
+                            )
+                        ]);
+                    }
                 }
             }
             $this->addElement('simpleNote', 'inherited_groups', [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/application/forms/IcingaServiceForm.php 
new/icingaweb2-module-director-1.8.1/application/forms/IcingaServiceForm.php
--- 
old/icingaweb2-module-director-1.8.0/application/forms/IcingaServiceForm.php    
    2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/application/forms/IcingaServiceForm.php    
    2021-07-13 10:18:55.000000000 +0200
@@ -139,6 +139,14 @@
         } else {
             $this->addOverrideHint();
             $group = $this->getDisplayGroup('custom_fields');
+            if (! $group) {
+                foreach ($this->getDisplayGroups() as $groupName => 
$eventualGroup) {
+                    if (preg_match('/^custom_fields:/', $groupName)) {
+                        $group = $eventualGroup;
+                        break;
+                    }
+                }
+            }
             if ($group) {
                 $elements = $group->getElements();
                 $group->setElements([$this->getElement('inheritance_hint')]);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/application/views/scripts/phperror/dependencies.phtml
 
new/icingaweb2-module-director-1.8.1/application/views/scripts/phperror/dependencies.phtml
--- 
old/icingaweb2-module-director-1.8.0/application/views/scripts/phperror/dependencies.phtml
  2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/application/views/scripts/phperror/dependencies.phtml
  2021-07-13 10:18:55.000000000 +0200
@@ -10,62 +10,5 @@
 
 <div class="content">
 <p class="legacy-error"><?= $this->escape($this->message) ?></p>
-<table class="common-table table-row-selectable">
-<thead>
-<tr>
-    <th><?= $this->translate('Module name') ?></th>
-    <th><?= $this->translate('Required') ?></th>
-    <th><?= $this->translate('Installed') ?></th>
-</tr>
-</thead>
-<tbody data-base-target="_next">
-<?php
-
-foreach ($this->dependencies as $module => $required) {
-    /** @var Manager $this->modules */
-    if ($modules->hasEnabled($module)) {
-        $installed = $modules->getModule($module, false)->getVersion();
-        $installed = \ltrim($installed, 'v'); // v0.6.0 VS 0.6.0
-        if (\preg_match('/^([<>=]+)\s*v?(\d+\.\d+\.\d+)$/', $required, 
$match)) {
-            $operator = $match[1];
-            $vRequired = $match[2];
-            if (\version_compare($installed, $vRequired, $operator)) {
-                $icon = 'ok';
-            } else {
-                $icon = 'cancel';
-            }
-        } else {
-            $icon = 'cancel';
-        }
-        $link = $this->qlink(
-                $module,
-                'config/module',
-                ['name' => $module],
-                ['class' => "icon-$icon"]
-        );
-    } elseif ($modules->hasInstalled($module)) {
-        $installed = $this->translate('disabled');
-        $link = $this->qlink($module, 'config/module', ['name' => $module], 
['class' => 'icon-cancel']);
-    } else {
-        $installed = $this->translate('missing');
-        $link = sprintf(
-            '<a href="#" class="icon-cancel">%s</a> (<a 
href="https://github.com/Icinga/icingaweb2-module-%s";'
-            . ' target="_blank" rel="noreferrer">%s</a>)',
-            $this->escape($module),
-            $this->escape($module),
-            $this->translate('more')
-        );
-    }
-
-    \printf(
-        '<tr><td>%s</a></td><td>%s</td><td>%s</td></tr>',
-        $link,
-        $this->escape($required),
-        $this->escape($installed)
-    );
-}
-
-?>
-</tbody>
-</table>
+<?= $this->table ?>
 </div>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/doc/02-Installation.md 
new/icingaweb2-module-director-1.8.1/doc/02-Installation.md
--- old/icingaweb2-module-director-1.8.0/doc/02-Installation.md 2020-12-15 
14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/doc/02-Installation.md 2021-07-13 
10:18:55.000000000 +0200
@@ -102,7 +102,7 @@
     ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules"
     REPO_URL="https://github.com/icinga/icingaweb2-module-director";
     TARGET_DIR="${ICINGAWEB_MODULEPATH}/director"
-    MODULE_VERSION="1.8.0"
+    MODULE_VERSION="1.8.1"
     URL="${REPO_URL}/archive/v${MODULE_VERSION}.tar.gz"
     install -d -m 0755 "${TARGET_DIR}"
     wget -q -O - "$URL" | tar xfz - -C "${TARGET_DIR}" --strip-components 1
@@ -119,7 +119,7 @@
     ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules"
     REPO_URL="https://github.com/icinga/icingaweb2-module-director";
     TARGET_DIR="${ICINGAWEB_MODULEPATH}/director"
-    MODULE_VERSION="1.8.0"
+    MODULE_VERSION="1.8.1"
     git clone "${REPO_URL}" "${TARGET_DIR}" --branch v${MODULE_VERSION}
 
 You can now directly use our current GIT master or check out a specific 
version.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/icingaweb2-module-director-1.8.0/doc/82-Changelog.md 
new/icingaweb2-module-director-1.8.1/doc/82-Changelog.md
--- old/icingaweb2-module-director-1.8.0/doc/82-Changelog.md    2020-12-15 
14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/doc/82-Changelog.md    2021-07-13 
10:18:55.000000000 +0200
@@ -4,6 +4,39 @@
 Please make sure to always read our [Upgrading](05-Upgrading.md) documentation
 before switching to a new version.
 
+1.8.1
+-----
+
+### Fixed issues
+* You can find issues and feature requests related to this release on our
+  
[roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/24?closed=1)
+
+### User Interface
+* FIX: show Override button when all Fields belong to Field Categories (#2303)
+* FIX: don't fail when showing a Host overriding multiple inherited groups 
(#2253)
+* FIX: deal with inherited values which are invalid for a select box (#2288)
+* FIX: Service Set preview inline Service Template links (#2334)
+* FIX: show Services applied with Rules involving applied Hostgroups (#2313)
+* FIX: show "deactivated" services as such also for read-only users (#2344)
+* FIX: Overrides for Services belonging to Sets on root Host Templates (#2333)
+* FIX: show no header tabs for search result in web 2.8+ (#2141)
+* FIX: show and link dependencies for web 2.9+ (#2354)
+
+### Icinga Configuration
+* FIX: rare race condition, where generated config might miss some files 
(#2351)
+
+### Icinga API
+* FIX: use Icinga 2's generate-ticket API, required for v2.13.0 (#2348)
+
+### Import and Sync
+* FIX: Purge didn't remove more than 1000 services at once (#2339)
+
+### Automation, User Interface
+* FIX: error message wording on failing related (or parent) object ref (#2224)
+
+### REST API
+* FIX: creating scheduled downtime via api failed (#1879)
+
 1.8.0
 -----
 
@@ -87,6 +120,7 @@
 ### Icinga Agent handling
 * FIX: Linux Agent installer now fails when unable to retrieve a certificate
 * FEATURE: Linux Agent installer now supports Alpine Linux (#2216)
+* FEATURE: Icinga for Windows support (#2147)
 
 ### REST API
 * FEATURE: Self Service API ignores empty/missing properties (e.g. no address)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Application/Dependency.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Application/Dependency.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Application/Dependency.php
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Application/Dependency.php
    2021-07-13 10:18:55.000000000 +0200
@@ -0,0 +1,113 @@
+<?php
+
+namespace Icinga\Module\Director\Application;
+
+class Dependency
+{
+    /** @var string */
+    protected $name;
+
+    /** @var string|null */
+    protected $installedVersion;
+
+    /** @var bool|null */
+    protected $enabled;
+
+    /** @var string */
+    protected $operator;
+
+    /** @var string */
+    protected $requiredVersion;
+
+    /** @var string */
+    protected $requirement;
+
+    /**
+     * Dependency constructor.
+     * @param string $name         Usually a module name
+     * @param string $requirement  e.g. >=1.7.0
+     * @param string $installedVersion
+     * @param bool $enabled
+     */
+    public function __construct($name, $requirement, $installedVersion = null, 
$enabled = null)
+    {
+        $this->name = $name;
+        $this->setRequirement($requirement);
+        if ($installedVersion !== null) {
+            $this->setInstalledVersion($installedVersion);
+        }
+        if ($enabled !== null) {
+            $this->setEnabled($enabled);
+        }
+    }
+
+    public function setRequirement($requirement)
+    {
+        if (preg_match('/^([<>=]+)\s*v?(\d+\.\d+\.\d+)$/', $requirement, 
$match)) {
+            $this->operator = $match[1];
+            $this->requiredVersion = $match[2];
+            $this->requirement = $requirement;
+        } else {
+            throw new \InvalidArgumentException("'$requirement' is not a valid 
version constraint");
+        }
+    }
+
+    /**
+     * @return bool
+     */
+    public function isInstalled()
+    {
+        return $this->installedVersion !== null;
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getInstalledVersion()
+    {
+        return $this->installedVersion;
+    }
+
+    /**
+     * @param string $version
+     */
+    public function setInstalledVersion($version)
+    {
+        $this->installedVersion = ltrim($version, 'v'); // v0.6.0 VS 0.6.0
+    }
+
+    /**
+     * @return bool
+     */
+    public function isEnabled()
+    {
+        return $this->enabled === true;
+    }
+
+    /**
+     * @param bool $enabled
+     */
+    public function setEnabled($enabled = true)
+    {
+        $this->enabled = $enabled;
+    }
+
+    public function isSatisfied()
+    {
+        if (! $this->isInstalled() || ! $this->isEnabled()) {
+            return false;
+        }
+
+        return version_compare($this->installedVersion, 
$this->requiredVersion, $this->operator);
+    }
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function getRequirement()
+    {
+        return $this->requirement;
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Application/DependencyChecker.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Application/DependencyChecker.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Application/DependencyChecker.php
     1970-01-01 01:00:00.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Application/DependencyChecker.php
     2021-07-13 10:18:55.000000000 +0200
@@ -0,0 +1,73 @@
+<?php
+
+namespace Icinga\Module\Director\Application;
+
+use Icinga\Application\ApplicationBootstrap;
+use Icinga\Application\Modules\Module;
+use Icinga\Application\Version;
+
+class DependencyChecker
+{
+    /** @var ApplicationBootstrap */
+    protected $app;
+
+    /** @var \Icinga\Application\Modules\Manager */
+    protected $modules;
+
+    public function __construct(ApplicationBootstrap $app)
+    {
+        $this->app = $app;
+        $this->modules = $app->getModuleManager();
+    }
+
+    /**
+     * @param Module $module
+     * @return Dependency[]
+     */
+    public function getDependencies(Module $module)
+    {
+        $dependencies = [];
+        $isV290 = version_compare(Version::VERSION, '2.9.0', '>=');
+        foreach ($module->getDependencies() as $moduleName => $required) {
+            if ($isV290 && in_array($moduleName, ['ipl', 'reactbundle'], 
true)) {
+                continue;
+            }
+            $dependency = new Dependency($moduleName, $required);
+            $dependency->setEnabled($this->modules->hasEnabled($moduleName));
+            if ($this->modules->hasInstalled($moduleName)) {
+                
$dependency->setInstalledVersion($this->modules->getModule($moduleName, 
false)->getVersion());
+            }
+            $dependencies[] = $dependency;
+        }
+        if ($isV290) {
+            $libs = $this->app->getLibraries();
+            foreach ($module->getRequiredLibraries() as $libraryName => 
$required) {
+                $dependency = new Dependency($libraryName, $required);
+                if ($libs->has($libraryName)) {
+                    
$dependency->setInstalledVersion($libs->get($libraryName)->getVersion());
+                    $dependency->setEnabled();
+                }
+                $dependencies[] = $dependency;
+            }
+        }
+
+        return $dependencies;
+    }
+
+    //     if (version_compare(Version::VERSION, '2.9.0', 'ge')) {
+    //    }
+    /**
+     * @param Module $module
+     * @return bool
+     */
+    public function satisfiesDependencies(Module $module)
+    {
+        foreach ($this->getDependencies($module) as $dependency) {
+            if (! $dependency->isSatisfied()) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Core/CoreApi.php 
new/icingaweb2-module-director-1.8.1/library/Director/Core/CoreApi.php
--- old/icingaweb2-module-director-1.8.0/library/Director/Core/CoreApi.php      
2020-12-15 14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/library/Director/Core/CoreApi.php      
2021-07-13 10:18:55.000000000 +0200
@@ -123,15 +123,38 @@
         return $res[$name];
     }
 
-    public function getTicketSalt()
+    /**
+     * Get a PKI ticket for CSR auto-signing
+     *
+     * @param string $cn The host???s common name for which the ticket should 
be generated
+     *
+     * @return string|null
+     */
+    public function getTicket($cn)
     {
-        // TODO: api must not be the name!
-        $api = $this->getObject('api', 'ApiListeners', array('ticket_salt'));
-        if (isset($api->attrs->ticket_salt)) {
-            return $api->attrs->ticket_salt;
+        $r = $this->client()->post(
+            'actions/generate-ticket',
+            ['cn' => $cn]
+        );
+        if (! $r->succeeded()) {
+            throw new RuntimeException($r->getErrorMessage());
         }
 
-        return null;
+        $ticket = $r->getRaw('ticket');
+        if ($ticket === null) {
+            // RestApiResponse::succeeded() returns true if Icinga 2 reports 
an error in the results key, e.g.
+            // {
+            //     "results": [
+            //         {
+            //             "code": 500.0,
+            //             "status": "Ticket salt is not configured in 
ApiListener object"
+            //         }
+            //     ]
+            // }
+            throw new RuntimeException($r->getRaw('status', 'Ticket is 
empty'));
+        }
+
+        return $ticket;
     }
 
     public function checkHostNow($host)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/IcingaConfig/AgentWizard.php
 
new/icingaweb2-module-director-1.8.1/library/Director/IcingaConfig/AgentWizard.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/IcingaConfig/AgentWizard.php
  2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/IcingaConfig/AgentWizard.php
  2021-07-13 10:18:55.000000000 +0200
@@ -8,6 +8,7 @@
 use Icinga\Module\Director\Objects\IcingaHost;
 use Icinga\Module\Director\Objects\IcingaZone;
 use Icinga\Module\Director\Util;
+use LogicException;
 
 class AgentWizard
 {
@@ -15,12 +16,13 @@
 
     protected $host;
 
-    protected $salt;
-
     protected $parentZone;
 
     protected $parentEndpoints;
 
+    /** @var string PKI ticket */
+    protected $ticket;
+
     public function __construct(IcingaHost $host)
     {
         $this->host = $host;
@@ -96,29 +98,32 @@
         );
     }
 
-    public function setTicketSalt($salt)
-    {
-        $this->salt = $salt;
-        return $this;
-    }
-
+    /**
+     * Get the PKI ticket
+     *
+     * @return string
+     *
+     * @throws LogicException If ticket has not been set
+     */
     protected function getTicket()
     {
-        return Util::getIcingaTicket(
-            $this->getCertName(),
-            $this->getTicketSalt()
-        );
+        if ($this->ticket === null) {
+            throw new LogicException('Ticket is null');
+        }
+
+        return $this->ticket;
     }
 
-    protected function getTicketSalt()
+    /**
+     * Set the PKI ticket
+     *
+     * @param string $ticket
+     *
+     * @return $this
+     */
+    public function setTicket($ticket)
     {
-        if ($this->salt === null) {
-            throw new ProgrammingError('Requesting salt, but got none');
-            // TODO: No API, not yet. Pass in constructor or throw, still tbd
-            // $this->salt = $this->api()->getTicketSalt();
-        }
-
-        return $this->salt;
+        $this->ticket = $ticket;
     }
 
     protected function getCertName()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/IcingaConfig/IcingaConfig.php
 
new/icingaweb2-module-director-1.8.1/library/Director/IcingaConfig/IcingaConfig.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/IcingaConfig/IcingaConfig.php
 2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/IcingaConfig/IcingaConfig.php
 2021-07-13 10:18:55.000000000 +0200
@@ -411,25 +411,31 @@
         }
 
         $activity = $this->dbBin($this->getLastActivityChecksum());
-        $this->db->insert(
-            self::$table,
-            array(
+        $this->db->beginTransaction();
+        try {
+            $this->db->insert(self::$table, [
                 'duration'                => $this->generationTime,
                 'first_activity_checksum' => $activity,
                 'last_activity_checksum'  => $activity,
                 'checksum'                => 
$this->dbBin($this->getChecksum()),
-            )
-        );
-        /** @var IcingaConfigFile $file */
-        foreach ($this->files as $name => $file) {
-            $this->db->insert(
-                'director_generated_config_file',
-                array(
+            ]);
+            /** @var IcingaConfigFile $file */
+            foreach ($this->files as $name => $file) {
+                $this->db->insert('director_generated_config_file', [
                     'config_checksum' => $this->dbBin($this->getChecksum()),
                     'file_checksum'   => $this->dbBin($file->getChecksum()),
                     'file_path'       => $name,
-                )
-            );
+                ]);
+            }
+            $this->db->commit();
+        } catch (\Exception $e) {
+            try {
+                $this->db->rollBack();
+            } catch (\Exception $ignored) {
+                // Well...
+            }
+
+            throw $e;
         }
 
         return $this;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Import/PurgeStrategy/ImportRunBasedPurgeStrategy.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Import/PurgeStrategy/ImportRunBasedPurgeStrategy.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Import/PurgeStrategy/ImportRunBasedPurgeStrategy.php
  2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Import/PurgeStrategy/ImportRunBasedPurgeStrategy.php
  2021-07-13 10:18:55.000000000 +0200
@@ -71,14 +71,14 @@
             $columns = SyncUtils::getRootVariables(
                 SyncUtils::extractVariableNames($pattern)
             );
-
+            $resultForCombinedKey = array();
             foreach (array_chunk($result, 1000) as $keys) {
                 $rows = $runA->fetchRows($columns, null, $keys);
-                $result = array();
                 foreach ($rows as $row) {
-                    $result[] = SyncUtils::fillVariables($pattern, $row);
+                    $resultForCombinedKey[] = 
SyncUtils::fillVariables($pattern, $row);
                 }
             }
+            $result = $resultForCombinedKey;
         }
 
         if (empty($result)) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Objects/IcingaObject.php 
new/icingaweb2-module-director-1.8.1/library/Director/Objects/IcingaObject.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Objects/IcingaObject.php  
    2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Objects/IcingaObject.php  
    2021-07-13 10:18:55.000000000 +0200
@@ -535,7 +535,13 @@
                 $this->connection
             );
         } catch (NotFoundError $e) {
-            throw new RuntimeException($e->getMessage(), 0, $e);
+            // Hint: eventually a NotFoundError would be better
+            throw new RuntimeException(sprintf(
+                'Unable to load object referenced from %s "%s", %s',
+                $this->getShortTableName(),
+                $this->getObjectName(),
+                lcfirst($e->getMessage())
+            ), $e->getCode(), $e);
         }
 
         $this->reallySet($name, $object->get('id'));
@@ -2553,7 +2559,7 @@
             $type = 'templateChoiceHost';
         } elseif ($type === 'service_template_choice') {
             $type = 'TemplateChoiceService';
-        } elseif ($type === 'scheduled_downtime') {
+        } elseif ($type === 'scheduled_downtime' || $type === 
'scheduled-downtime') {
             $type = 'ScheduledDowntime';
         }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Objects/IcingaObjectImports.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Objects/IcingaObjectImports.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Objects/IcingaObjectImports.php
       2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Objects/IcingaObjectImports.php
       2021-07-13 10:18:55.000000000 +0200
@@ -4,6 +4,7 @@
 
 use Countable;
 use Exception;
+use Icinga\Exception\NotFoundError;
 use Iterator;
 use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
 use Icinga\Module\Director\IcingaConfig\IcingaConfigRenderer;
@@ -251,14 +252,23 @@
         $connection = $this->object->getConnection();
         /** @var IcingaObject $class */
         $class = $this->getImportClass();
-        if (is_array($this->object->getKeyName())) {
-            // Services only
-            $import = $class::load([
-                'object_name' => $name,
-                'object_type' => 'template'
-            ], $connection);
-        } else {
-            $import = $class::load($name, $connection);
+        try {
+            if (is_array($this->object->getKeyName())) {
+                // Services only
+                $import = $class::load([
+                    'object_name' => $name,
+                    'object_type' => 'template'
+                ], $connection);
+            } else {
+                $import = $class::load($name, $connection);
+            }
+        } catch (NotFoundError $e) {
+            throw new NotFoundError(sprintf(
+                'Unable to load parent referenced from %s "%s", %s',
+                $this->object->getShortTableName(),
+                $this->object->getObjectName(),
+                lcfirst($e->getMessage())
+            ), $e->getCode(), $e);
         }
 
         return $this->objects[$import->getObjectName()] = $import;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Objects/ObjectApplyMatches.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Objects/ObjectApplyMatches.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Objects/ObjectApplyMatches.php
        2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Objects/ObjectApplyMatches.php
        2021-07-13 10:18:55.000000000 +0200
@@ -213,10 +213,26 @@
     protected function __construct(IcingaObject $object)
     {
         $this->object = $object;
-        $this->flatObject = $object->toPlainObject(true, false);
+        $flat = $object->toPlainObject(true, false);
         // Sure, we are flat - but we might still want to match templates.
-        unset($this->flatObject->imports);
-        $this->flatObject->templates = $object->listFlatResolvedImportNames();
-        static::flattenVars($this->flatObject);
+        unset($flat->imports);
+        $flat->templates = $object->listFlatResolvedImportNames();
+        $this->addAppliedGroupsToFlatObject($flat, $object);
+        static::flattenVars($flat);
+        $this->flatObject = $flat;
+    }
+
+    protected function addAppliedGroupsToFlatObject($flat, IcingaObject 
$object)
+    {
+        if ($object instanceof IcingaHost) {
+            $appliedGroups = $object->getAppliedGroups();
+            if (! empty($appliedGroups)) {
+                if (isset($flat->groups)) {
+                    $flat->groups = array_merge($flat->groups, $appliedGroups);
+                } else {
+                    $flat->groups = $appliedGroups;
+                }
+            }
+        }
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Resolver/OverriddenVarsResolver.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Resolver/OverriddenVarsResolver.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Resolver/OverriddenVarsResolver.php
   2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Resolver/OverriddenVarsResolver.php
   2021-07-13 10:18:55.000000000 +0200
@@ -23,7 +23,11 @@
 
     public function resolveFor(IcingaHost $host, IcingaService $service = null)
     {
+        $overrides = [];
         $parents = $host->listFlatResolvedImportNames();
+        if (empty($parents)) {
+            return $overrides;
+        }
         $query = $this->db->select()->from(['hv' => 'icinga_host_var'], [
             'host_name' => 'h.object_name',
             'varvalue'  => 'hv.varvalue',
@@ -32,7 +36,6 @@
             'h.id = hv.host_id',
             []
         )->where('hv.varname = ?', $this->varName)->where('h.object_name IN 
(?)', $parents);
-        $overrides = [];
         foreach ($this->db->fetchAll($query) as $row) {
             if ($row->varvalue === null) {
                 continue;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/RestApi/IcingaObjectHandler.php
 
new/icingaweb2-module-director-1.8.1/library/Director/RestApi/IcingaObjectHandler.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/RestApi/IcingaObjectHandler.php
       2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/RestApi/IcingaObjectHandler.php
       2021-07-13 10:18:55.000000000 +0200
@@ -105,12 +105,7 @@
                 throw new NotFoundError('The host "%s" is not an agent', 
$host->getObjectName());
             }
 
-            $this->sendJson(
-                Util::getIcingaTicket(
-                    $host->getObjectName(),
-                    $this->api->getTicketSalt()
-                )
-            );
+            $this->sendJson($this->api->getTicket($host->getObjectName()));
 
             // TODO: find a better way to shut down. Currently, this avoids
             //       "not found" errors:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Util.php 
new/icingaweb2-module-director-1.8.1/library/Director/Util.php
--- old/icingaweb2-module-director-1.8.0/library/Director/Util.php      
2020-12-15 14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/library/Director/Util.php      
2021-07-13 10:18:55.000000000 +0200
@@ -81,11 +81,6 @@
         return bin2hex(substr($out, 0, $length));
     }
 
-    public static function getIcingaTicket($certname, $salt)
-    {
-        return self::pbkdf2('sha1', $certname, $salt, 50000, 20);
-    }
-
     public static function auth()
     {
         if (self::$auth === null) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Controller/ActionController.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Controller/ActionController.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Controller/ActionController.php
   2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Controller/ActionController.php
   2021-07-13 10:18:55.000000000 +0200
@@ -216,7 +216,8 @@
             $viewRenderer = new SimpleViewRenderer();
             $viewRenderer->replaceZendViewRenderer();
             $this->view = $viewRenderer->view;
-            if ($this->getOriginalUrl()->getParam('view') === 'compact') {
+            // Hint -> $this->view->compact is the only way since v2.8.0
+            if ($this->view->compact || 
$this->getOriginalUrl()->getParam('view') === 'compact') {
                 if ($this->view->controls) {
                     $this->controls()->getAttributes()->add('style', 'display: 
none;');
                 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Form/DirectorObjectForm.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Form/DirectorObjectForm.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Form/DirectorObjectForm.php
       2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Form/DirectorObjectForm.php
       2021-07-13 10:18:55.000000000 +0200
@@ -629,7 +629,7 @@
             if (is_bool($inherited)) {
                 $inherited = $inherited ? 'y' : 'n';
             }
-            if (array_key_exists($inherited, $multi)) {
+            if (is_scalar($inherited) && array_key_exists($inherited, $multi)) 
{
                 $multi[null] = $multi[$inherited] . sprintf($txtInherited, 
$inheritedFrom);
             } else {
                 $multi[null] = $this->translate($this->translate('- inherited 
-'));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Web/ObjectPreview.php 
new/icingaweb2-module-director-1.8.1/library/Director/Web/ObjectPreview.php
--- old/icingaweb2-module-director-1.8.0/library/Director/Web/ObjectPreview.php 
2020-12-15 14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/library/Director/Web/ObjectPreview.php 
2021-07-13 10:18:55.000000000 +0200
@@ -141,9 +141,13 @@
             return $match[1] . $match[2] . $match[3];
         }
 
+        $urlObjectType = $this->object->getShortTableName();
+        if ($urlObjectType === 'service_set') {
+            $urlObjectType = 'service';
+        }
         return $match[1] . Link::create(
             $match[2],
-            sprintf('director/' . $this->object->getShortTableName()),
+            sprintf("director/$urlObjectType"),
             ['name' => $match[2]]
         )->render() . $match[3];
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Web/SelfService.php 
new/icingaweb2-module-director-1.8.1/library/Director/Web/SelfService.php
--- old/icingaweb2-module-director-1.8.0/library/Director/Web/SelfService.php   
2020-12-15 14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/library/Director/Web/SelfService.php   
2021-07-13 10:18:55.000000000 +0200
@@ -226,9 +226,9 @@
         $certname = $host->getObjectName();
 
         try {
-            $ticket = Util::getIcingaTicket($certname, 
$this->api->getTicketSalt());
+            $ticket = $this->api->getTicket($host->getObjectName());
             $wizard = new AgentWizard($host);
-            $wizard->setTicketSalt($this->api->getTicketSalt());
+            $wizard->setTicket($ticket);
         } catch (Exception $e) {
             $c->add(Hint::error(sprintf(
                 $this->translate(
@@ -278,7 +278,7 @@
     public function handleLegacyAgentDownloads($os)
     {
         $wizard = new AgentWizard($this->host);
-        $wizard->setTicketSalt($this->api->getTicketSalt());
+        
$wizard->setTicket($this->api->getTicket($this->host->getObjectName()));
 
         switch ($os) {
             case 'windows-kickstart':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Table/Dependency/DependencyInfoTable.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Table/Dependency/DependencyInfoTable.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Table/Dependency/DependencyInfoTable.php
  1970-01-01 01:00:00.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Table/Dependency/DependencyInfoTable.php
  2021-07-13 10:18:55.000000000 +0200
@@ -0,0 +1,101 @@
+<?php
+
+namespace Icinga\Module\Director\Web\Table\Dependency;
+
+use Icinga\Application\Modules\Module;
+use Icinga\Module\Director\Application\DependencyChecker;
+use Icinga\Web\Url;
+
+class DependencyInfoTable
+{
+    protected $module;
+
+    protected $checker;
+
+    public function __construct(DependencyChecker $checker, Module $module)
+    {
+        $this->module = $module;
+        $this->checker = $checker;
+    }
+
+    protected function linkToModule($name, $icon)
+    {
+        return Html::link(
+            Html::escape($name),
+            Html::webUrl('config/module', ['name' => $name]),
+            [
+                'class' => "icon-$icon"
+            ]
+        );
+    }
+
+    public function render()
+    {
+        $html = '<table class="common-table table-row-selectable">
+<thead>
+<tr>
+    <th>' . Html::escape($this->translate('Module name')) . '</th>
+    <th>' . Html::escape($this->translate('Required')) . '</th>
+    <th>' . Html::escape($this->translate('Installed')) . '</th>
+</tr>
+</thead>
+<tbody data-base-target="_next">
+';
+        foreach ($this->checker->getDependencies($this->module) as 
$dependency) {
+            $name = $dependency->getName();
+            $isLibrary = substr($name, 0, 11) === 'icinga-php-';
+            $rowAttributes = $isLibrary ? ['data-base-target' => '_self'] : 
null;
+            if ($dependency->isSatisfied()) {
+                if ($dependency->isSatisfied()) {
+                    $icon = 'ok';
+                } else {
+                    $icon = 'cancel';
+                }
+                $link = $isLibrary ? $this->noLink($name, $icon) : 
$this->linkToModule($name, $icon);
+                $installed = $dependency->getInstalledVersion();
+            } elseif ($dependency->isInstalled()) {
+                $installed = sprintf('%s (%s)', 
$dependency->getInstalledVersion(), $this->translate('disabled'));
+                $link = $this->linkToModule($name, 'cancel');
+            } else {
+                $installed = $this->translate('missing');
+                $repository = $isLibrary ? $name : "icingaweb2-module-$name";
+                $link = sprintf(
+                    '%s (%s)',
+                    $this->noLink($name, 'cancel'),
+                    Html::linkToGitHub(Html::escape($this->translate('more')), 
'Icinga', $repository)
+                );
+            }
+
+            $html .= $this->htmlRow([
+                $link,
+                Html::escape($dependency->getRequirement()),
+                Html::escape($installed)
+            ], $rowAttributes);
+        }
+
+        return $html . '</tbody>
+</table>
+';
+    }
+
+    protected function noLink($label, $icon)
+    {
+        return Html::link(Html::escape($label), 
Url::fromRequest()->with('rnd', rand(1, 100000)), [
+            'class' => "icon-$icon"
+        ]);
+    }
+
+    protected function translate($string)
+    {
+        return \mt('director', $string);
+    }
+
+    protected function htmlRow(array $cols, $rowAttributes)
+    {
+        $content = '';
+        foreach ($cols as $escapedContent) {
+            $content .= Html::tag('td', null, $escapedContent);
+        }
+        return Html::tag('tr', $rowAttributes, $content);
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Table/Dependency/Html.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Table/Dependency/Html.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Table/Dependency/Html.php
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Table/Dependency/Html.php
 2021-07-13 10:18:55.000000000 +0200
@@ -0,0 +1,74 @@
+<?php
+
+namespace Icinga\Module\Director\Web\Table\Dependency;
+
+use Icinga\Web\Url;
+use InvalidArgumentException;
+
+/**
+ * Minimal HTML helper, as we might be forced to run without ipl
+ */
+class Html
+{
+    public static function tag($tag, $attributes = [], $escapedContent = null)
+    {
+        $result = "<$tag";
+        if (! empty($attributes)) {
+            foreach ($attributes as $name => $value) {
+                if (! preg_match('/^[a-z][a-z0-9:-]*$/i', $name)) {
+                    throw new InvalidArgumentException("Invalid attribute 
name: '$name'");
+                }
+
+                $result .= " $name=\"" . self::escapeAttributeValue($value) . 
'"';
+            }
+        }
+
+        return "$result>$escapedContent</$tag>";
+    }
+
+    public static function webUrl($path, $params)
+    {
+        return Url::fromPath($path, $params);
+    }
+
+    public static function link($escapedLabel, $url, $attributes = [])
+    {
+        return static::tag('a', [
+            'href' => $url,
+        ] + $attributes, $escapedLabel);
+    }
+
+    public static function linkToGitHub($escapedLabel, $namespace, $repository)
+    {
+        return static::link(
+            $escapedLabel,
+            'https://github.com/' . urlencode($namespace) . '/' . 
urlencode($repository),
+            [
+                'target' => '_blank',
+                'rel'    => 'noreferrer',
+                'class'  => 'icon-forward'
+            ]
+        );
+    }
+
+    protected static function escapeAttributeValue($value)
+    {
+        $value = str_replace('"', '&quot;', $value);
+        // Escape ambiguous ampersands
+        return preg_replace_callback('/&[0-9A-Z]+;/i', function ($match) {
+            $subject = $match[0];
+
+            if (htmlspecialchars_decode($subject, ENT_COMPAT | ENT_HTML5) === 
$subject) {
+                // Ambiguous ampersand
+                return str_replace('&', '&amp;', $subject);
+            }
+
+            return $subject;
+        }, $value);
+    }
+
+    public static function escape($any)
+    {
+        return htmlspecialchars($any);
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Table/IcingaServiceSetServiceTable.php
 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Table/IcingaServiceSetServiceTable.php
--- 
old/icingaweb2-module-director-1.8.0/library/Director/Web/Table/IcingaServiceSetServiceTable.php
    2020-12-15 14:44:54.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/library/Director/Web/Table/IcingaServiceSetServiceTable.php
    2021-07-13 10:18:55.000000000 +0200
@@ -105,10 +105,10 @@
     {
         if ($this->readonly) {
             if ($this->highlightedService === $row->service) {
-                return Html::tag('span', ['class' => 'icon-right-big'], 
$row->service);
-            } else {
-                return $row->service;
+                return Html::tag('span', ['class' => 'ro-service 
icon-right-big'], $row->service);
             }
+
+            return Html::tag('span', ['class' => 'ro-service'], $row->service);
         }
 
         if ($this->affectedHost) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/icingaweb2-module-director-1.8.0/module.info 
new/icingaweb2-module-director-1.8.1/module.info
--- old/icingaweb2-module-director-1.8.0/module.info    2020-12-15 
14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/module.info    2021-07-13 
10:18:55.000000000 +0200
@@ -1,5 +1,5 @@
 Name: Icinga Director
-Version: 1.8.0
+Version: 1.8.1
 Depends: reactbundle (>=0.7.0), ipl (>=0.3.0), incubator (>=0.6.0)
 Description: Director - Config tool for Icinga 2
  Icinga Director is a configuration tool that has been designed to make
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/public/css/module.less 
new/icingaweb2-module-director-1.8.1/public/css/module.less
--- old/icingaweb2-module-director-1.8.0/public/css/module.less 2020-12-15 
14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/public/css/module.less 2021-07-13 
10:18:55.000000000 +0200
@@ -453,6 +453,9 @@
     text-decoration: line-through;
   }
 }
+.strike-links span.ro-service {
+  text-decoration: line-through;
+}
 
 // TODO: figure out whether form.editor and filter-related CSS is still 
required
 div.filter > form.search, div.filter > a {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/icingaweb2-module-director-1.8.0/run.php 
new/icingaweb2-module-director-1.8.1/run.php
--- old/icingaweb2-module-director-1.8.0/run.php        2020-12-15 
14:44:54.000000000 +0100
+++ new/icingaweb2-module-director-1.8.1/run.php        2021-07-13 
10:18:55.000000000 +0200
@@ -1,6 +1,7 @@
 <?php
 
 use Icinga\Application\Modules\Module;
+use Icinga\Module\Director\Application\DependencyChecker;
 
 if (version_compare(PHP_VERSION, '5.6.0') < 0) {
     include __DIR__ . '/run-php5.3.php';
@@ -8,20 +9,8 @@
 }
 
 /** @var Module $this */
-$modules = $this->app->getModuleManager();
-foreach ($this->getDependencies() as $module => $required) {
-    if ($modules->hasEnabled($module)) {
-        $installed = $modules->getModule($module, false)->getVersion();
-        $installed = ltrim($installed, 'v'); // v0.6.0 VS 0.6.0
-        if (preg_match('/^([<>=]+)\s*v?(\d+\.\d+\.\d+)$/', $required, $match)) 
{
-            $operator = $match[1];
-            $vRequired = $match[2];
-            if (version_compare($installed, $vRequired, $operator)) {
-                continue;
-            }
-        }
-    }
-
+$checker = new DependencyChecker($this->app);
+if (! $checker->satisfiesDependencies($this)) {
     include __DIR__ . '/run-missingdeps.php';
     return;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/icingaweb2-module-director-1.8.0/test/php/library/Director/Application/DependencyTest.php
 
new/icingaweb2-module-director-1.8.1/test/php/library/Director/Application/DependencyTest.php
--- 
old/icingaweb2-module-director-1.8.0/test/php/library/Director/Application/DependencyTest.php
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/icingaweb2-module-director-1.8.1/test/php/library/Director/Application/DependencyTest.php
       2021-07-13 10:18:55.000000000 +0200
@@ -0,0 +1,72 @@
+<?php
+
+namespace Tests\Icinga\Module\Director\Application;
+
+use Icinga\Module\Director\Application\Dependency;
+use Icinga\Module\Director\Test\BaseTestCase;
+
+class DependencyTest extends BaseTestCase
+{
+    public function testIsNotInstalled()
+    {
+        $dependency = new Dependency('something', '>=0.3.0');
+        $this->assertFalse($dependency->isInstalled());
+    }
+
+    public function testNotSatisfiedWhenNotInstalled()
+    {
+        $dependency = new Dependency('something', '>=0.3.0');
+        $this->assertFalse($dependency->isSatisfied());
+    }
+
+    public function testIsInstalled()
+    {
+        $dependency = new Dependency('something', '>=0.3.0');
+        $dependency->setInstalledVersion('1.10.0');
+        $this->assertTrue($dependency->isInstalled());
+    }
+
+    public function testNotEnabled()
+    {
+        $dependency = new Dependency('something', '>=0.3.0');
+        $this->assertFalse($dependency->isEnabled());
+    }
+
+    public function testIsEnabled()
+    {
+        $dependency = new Dependency('something', '>=0.3.0');
+        $dependency->setEnabled();
+        $this->assertTrue($dependency->isEnabled());
+    }
+
+    public function testNotSatisfiedWhenNotEnabled()
+    {
+        $dependency = new Dependency('something', '>=0.3.0');
+        $dependency->setInstalledVersion('1.10.0');
+        $this->assertFalse($dependency->isSatisfied());
+    }
+
+    public function testSatisfiedWhenEqual()
+    {
+        $dependency = new Dependency('something', '>=0.3.0');
+        $dependency->setInstalledVersion('0.3.0');
+        $dependency->setEnabled();
+        $this->assertTrue($dependency->isSatisfied());
+    }
+
+    public function testSatisfiedWhenGreater()
+    {
+        $dependency = new Dependency('something', '>=0.3.0');
+        $dependency->setInstalledVersion('0.10.0');
+        $dependency->setEnabled();
+        $this->assertTrue($dependency->isSatisfied());
+    }
+
+    public function testNotSatisfiedWhenSmaller()
+    {
+        $dependency = new Dependency('something', '>=20.3.0');
+        $dependency->setInstalledVersion('4.999.999');
+        $dependency->setEnabled();
+        $this->assertFalse($dependency->isSatisfied());
+    }
+}

Reply via email to