From 14b56151aae03ae1a7f114bc8a6439545e1ddf22 Mon Sep 17 00:00:00 2001
From: Johannes Meyer <johannes.meyer@netways.de>
Date: Tue, 27 Aug 2013 14:27:31 +0200
Subject: [PATCH 1/3] Move configuration and preference handling to Form base
 class

Moved setConfiguration, setUserPreferences and getUserPreferences
to our Form base class due to some redundancies.

refs #4581
---
 application/forms/Config/LoggingForm.php                  | 5 ++++-
 test/php/application/forms/Preference/GeneralFormTest.php | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/application/forms/Config/LoggingForm.php b/application/forms/Config/LoggingForm.php
index 5a06994c2..dc90a24d8 100644
--- a/application/forms/Config/LoggingForm.php
+++ b/application/forms/Config/LoggingForm.php
@@ -156,7 +156,10 @@ class LoggingForm extends Form
                 'label'     => 'Debug Log Path',
                 'required'  => $this->shouldDisplayDebugLog($debug),
                 'condition' => $this->shouldDisplayDebugLog($debug),
-                'value'     => $debug->get('target', $this->getBaseDir() . '/var/log/icinga2.debug.log'),
+                'value'     => $debug->get(
+                    'target',
+                    $this->getBaseDir() . '/var/log/icinga2.debug.log'
+                ),
                 'helptext'  => 'Set the path to the debug log'
             )
         );
diff --git a/test/php/application/forms/Preference/GeneralFormTest.php b/test/php/application/forms/Preference/GeneralFormTest.php
index 51ccd13b4..effcdb4f8 100644
--- a/test/php/application/forms/Preference/GeneralFormTest.php
+++ b/test/php/application/forms/Preference/GeneralFormTest.php
@@ -46,6 +46,7 @@ require_once BaseTestCase::$libDir . '/Util/DateTimeFactory.php';
 // @codingStandardsIgnoreEnd
 
 use \DateTimeZone;
+use \Zend_Config;
 use \Icinga\User\Preferences;
 use \Zend_View_Helper_DateFormat;
 use \Icinga\Util\DateTimeFactory;

From 4d040fd761472751555b43305f02f0ada619f9ce Mon Sep 17 00:00:00 2001
From: Johannes Meyer <johannes.meyer@netways.de>
Date: Fri, 30 Aug 2013 10:37:32 +0200
Subject: [PATCH 2/3] Adjust command forms and tests

Made those command forms using the DateTimePicker
element compatible with its new validation.

refs #4581
---
 application/forms/Config/LoggingForm.php                  | 5 +----
 test/php/application/forms/Preference/GeneralFormTest.php | 1 -
 2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/application/forms/Config/LoggingForm.php b/application/forms/Config/LoggingForm.php
index dc90a24d8..5a06994c2 100644
--- a/application/forms/Config/LoggingForm.php
+++ b/application/forms/Config/LoggingForm.php
@@ -156,10 +156,7 @@ class LoggingForm extends Form
                 'label'     => 'Debug Log Path',
                 'required'  => $this->shouldDisplayDebugLog($debug),
                 'condition' => $this->shouldDisplayDebugLog($debug),
-                'value'     => $debug->get(
-                    'target',
-                    $this->getBaseDir() . '/var/log/icinga2.debug.log'
-                ),
+                'value'     => $debug->get('target', $this->getBaseDir() . '/var/log/icinga2.debug.log'),
                 'helptext'  => 'Set the path to the debug log'
             )
         );
diff --git a/test/php/application/forms/Preference/GeneralFormTest.php b/test/php/application/forms/Preference/GeneralFormTest.php
index effcdb4f8..51ccd13b4 100644
--- a/test/php/application/forms/Preference/GeneralFormTest.php
+++ b/test/php/application/forms/Preference/GeneralFormTest.php
@@ -46,7 +46,6 @@ require_once BaseTestCase::$libDir . '/Util/DateTimeFactory.php';
 // @codingStandardsIgnoreEnd
 
 use \DateTimeZone;
-use \Zend_Config;
 use \Icinga\User\Preferences;
 use \Zend_View_Helper_DateFormat;
 use \Icinga\Util\DateTimeFactory;

From a0e63a1320e80db2dd85c0337b36ffe02cc40531 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jannis=20Mo=C3=9Fhammer?= <jannis.mosshammer@netways.de>
Date: Fri, 30 Aug 2013 17:42:39 +0200
Subject: [PATCH 3/3] Fix error message and move validation in own
 DateTimeValidator

refs #4581
refs #4632
---
 application/views/helpers/DateFormat.php      |   7 +-
 .../Web/Form/Element/DateTimePicker.php       |  66 +++-----
 .../Web/Form/Validator/DateTimeValidator.php  | 158 ++++++++++++++++++
 .../Web/Form/Element/DateTimePickerTest.php   |  16 +-
 4 files changed, 200 insertions(+), 47 deletions(-)
 create mode 100644 library/Icinga/Web/Form/Validator/DateTimeValidator.php

diff --git a/application/views/helpers/DateFormat.php b/application/views/helpers/DateFormat.php
index 1febf5eeb..3816c291a 100644
--- a/application/views/helpers/DateFormat.php
+++ b/application/views/helpers/DateFormat.php
@@ -9,6 +9,7 @@ use \Icinga\Application\Icinga;
 use \Icinga\Application\Config as IcingaConfig;
 use \Icinga\Util\DateTimeFactory;
 use \Zend_Controller_Request_Http;
+use \Icinga\Web\Form\Validator\DateTimeValidator;
 
 /**
  * Helper to format date and time. Utilizes DateTimeFactory to ensure time zone awareness
@@ -60,7 +61,11 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
     public function format($timestamp, $format)
     {
         $dt = DateTimeFactory::create();
-        $dt->setTimestamp($timestamp);
+        if (DateTimeValidator::isUnixTimestamp($timestamp)) {
+            $dt->setTimestamp($timestamp);
+        } else {
+            return $timestamp;
+        }
         return $dt->format($format);
     }
 
diff --git a/library/Icinga/Web/Form/Element/DateTimePicker.php b/library/Icinga/Web/Form/Element/DateTimePicker.php
index 096707940..934a13657 100644
--- a/library/Icinga/Web/Form/Element/DateTimePicker.php
+++ b/library/Icinga/Web/Form/Element/DateTimePicker.php
@@ -28,9 +28,10 @@
 
 namespace Icinga\Web\Form\Element;
 
-use \Zend_Form_Element_Xhtml;
+use Icinga\Web\Form\Validator\DateTimeValidator;
+use \Zend_Form_Element_Text;
+use \Zend_Form_Element;
 use \Icinga\Util\DateTimeFactory;
-use \Icinga\Exception\ProgrammingError;
 
 /**
  * Datetime form element which returns the input as Unix timestamp after the input has been proven valid. Utilizes
@@ -38,7 +39,7 @@ use \Icinga\Exception\ProgrammingError;
  *
  * @see isValid()
  */
-class DateTimePicker extends Zend_Form_Element_Xhtml
+class DateTimePicker extends Zend_Form_Element_Text
 {
     /**
      * View helper to use
@@ -46,6 +47,12 @@ class DateTimePicker extends Zend_Form_Element_Xhtml
      */
     public $helper = 'formDateTime';
 
+    /**
+     * The validator used for datetime validation
+     * @var DateTimeValidator
+     */
+    private $dateValidator;
+
     /**
      * Valid formats to check user input against
      * @var array
@@ -53,16 +60,18 @@ class DateTimePicker extends Zend_Form_Element_Xhtml
     public $patterns;
 
     /**
-     * Check whether a variable is a Unix timestamp
+     * Create a new DateTimePicker
      *
-     * @param   mixed   $timestamp
-     * @return  bool
+     * @param array|string|\Zend_Config $spec
+     * @param null $options
+     * @see Zend_Form_Element::__construct()
      */
-    public function isUnixTimestamp($timestamp)
+    public function __construct($spec, $options = null)
     {
-        return (is_int($timestamp) || ctype_digit($timestamp))
-            && ($timestamp <= PHP_INT_MAX)
-            && ($timestamp >= ~PHP_INT_MAX);
+        parent::__construct($spec, $options);
+        $this->dateValidator = new DateTimeValidator($this->patterns);
+        $this->addValidator($this->dateValidator);
+
     }
 
     /**
@@ -77,40 +86,17 @@ class DateTimePicker extends Zend_Form_Element_Xhtml
      */
     public function isValid($value, $context = null)
     {
+        // Overwrite the internal validator to use
+
         if (!parent::isValid($value, $context)) {
             return false;
         }
-
-        if (!is_string($value) && !is_int($value)) {
-            $this->addErrorMessage(
-                _('Invalid type given. Date/time string or Unix timestamp expected')
-            );
-            return false;
+        $pattern = $this->dateValidator->getValidPattern();
+        if (!$pattern) {
+            $this->setValue($value);
+            return true;
         }
-
-        if ($this->isUnixTimestamp($value)) {
-            $dt = DateTimeFactory::create();
-            $dt->setTimestamp($value);
-        } else {
-            if (!isset($this->patterns)) {
-                throw new ProgrammingError('Cannot parse datetime string without any pattern');
-            }
-
-            $match_found = false;
-            foreach ($this->patterns as $pattern) {
-                $dt = DateTimeFactory::parse($value, $pattern);
-                if ($dt !== false && $dt->format($pattern) === $value) {
-                    $match_found = true;
-                    break;
-                }
-            }
-            if (!$match_found) {
-                return false;
-            }
-        }
-
-        $this->setValue($dt->getTimestamp());
-
+        $this->setValue(DateTimeFactory::parse($value, $pattern)->getTimestamp());
         return true;
     }
 }
diff --git a/library/Icinga/Web/Form/Validator/DateTimeValidator.php b/library/Icinga/Web/Form/Validator/DateTimeValidator.php
new file mode 100644
index 000000000..292ab00c7
--- /dev/null
+++ b/library/Icinga/Web/Form/Validator/DateTimeValidator.php
@@ -0,0 +1,158 @@
+<?php
+// {{{ICINGA_LICENSE_HEADER}}}
+/**
+ * This file is part of Icinga 2 Web.
+ *
+ * Icinga 2 Web - Head for multiple monitoring backends.
+ * Copyright (C) 2013 Icinga Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * @copyright 2013 Icinga Development Team <info@icinga.org>
+ * @license   http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
+ * @author    Icinga Development Team <info@icinga.org>
+ */
+// {{{ICINGA_LICENSE_HEADER}}}
+
+
+namespace Icinga\Web\Form\Validator;
+
+use \Icinga\Util\DateTimeFactory;
+use \Zend_Validate_Abstract;
+use \Icinga\Exception\ProgrammingError;
+
+/**
+ * Validator that checks if a textfield contains a correct date format
+ */
+class DateTimeValidator extends Zend_Validate_Abstract
+{
+    /**
+     * Array of allowed patterns for datetime input
+     *
+     * @var array
+     */
+    private $patterns     = array();
+
+    /**
+     * If the input is not a timestamp this contains the pattern that
+     * matched the input
+     *
+     * @var string|bool
+     */
+    private $validPattern = false;
+
+    /**
+     * Error templates
+     *
+     * @var array
+     *
+     * @see Zend_Validate_Abstract::$_messageTemplates
+     */
+    // @codingStandardsIgnoreStart
+    protected $_messageTemplates = array();
+    // @codingStandardsIgnoreEnd
+
+    /**
+     * Create this validator
+     *
+     * @param array $patterns   Array containing all allowed patterns as strings
+     */
+    public function __construct(array $patterns)
+    {
+        $this->patterns = $patterns;
+        $this->_messageTemplates = array(
+            'INVALID_TYPE'          => 'Invalid type given. Date/time string or Unix timestamp expected',
+            'NO_MATCHING_PATTERN'   => 'Invalid format given, valid formats are ' . $this->getAllowedPatternList()
+        );
+    }
+
+    /**
+     * Check whether a variable is a Unix timestamp
+     *
+     * @param   mixed   $timestamp
+     * @return  bool
+     */
+    public static function isUnixTimestamp($timestamp)
+    {
+        return (is_int($timestamp) || ctype_digit($timestamp))
+        && ($timestamp <= PHP_INT_MAX)
+        && ($timestamp >= ~PHP_INT_MAX);
+    }
+
+    /**
+     * Returns a printable string containing all configured patterns
+     *
+     * @return string
+     */
+    private function getAllowedPatternList()
+    {
+        return '"' . join('","', $this->patterns) . '"';
+    }
+
+
+    /**
+     * Validate the input value and set the value of @see validPattern if the input machtes a pattern
+     *
+     * @param   string  $value      The format string to validate
+     * @param   null    $context    The form context (ignored)
+     *
+     * @return  bool True when the input is valid, otherwise false
+     *
+     * @see     Zend_Validate_Abstract::isValid()
+     */
+    public function isValid($value, $context = null)
+    {
+        $this->validPattern = false;
+        if (!is_string($value) && !is_int($value)) {
+            $this->error('INVALID_TYPE');
+            return false;
+        }
+
+        if ($this->isUnixTimestamp($value)) {
+            $dt = DateTimeFactory::create();
+            $dt->setTimestamp($value);
+        } else {
+            if (!isset($this->patterns)) {
+                throw new ProgrammingError('There are no allowed timeformats configured');
+            }
+
+            $match_found = false;
+            foreach ($this->patterns as $pattern) {
+                $dt = DateTimeFactory::parse($value, $pattern);
+                if ($dt !== false && $dt->format($pattern) === $value) {
+                    $match_found = true;
+                    $this->validPattern = $pattern;
+                    break;
+                }
+            }
+            if (!$match_found) {
+                $this->_error('NO_MATCHING_PATTERN');
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Return the matched pattern if any or false if input is a timestamp
+     *
+     * @return bool|string      False if input was a timestamp otherwise string with the dateformat pattern
+     */
+    public function getValidPattern()
+    {
+        return $this->validPattern;
+    }
+}
diff --git a/test/php/library/Icinga/Web/Form/Element/DateTimePickerTest.php b/test/php/library/Icinga/Web/Form/Element/DateTimePickerTest.php
index bdf78f60f..5d35a5de0 100644
--- a/test/php/library/Icinga/Web/Form/Element/DateTimePickerTest.php
+++ b/test/php/library/Icinga/Web/Form/Element/DateTimePickerTest.php
@@ -1,19 +1,23 @@
 <?php
 
 namespace Test\Icinga\Web\Form\Element;
+use Icinga\Test\BaseTestCase;
 
+require_once 'Zend/Form/Element/Text.php';
 require_once 'Zend/Form/Element/Xhtml.php';
-require_once realpath(__DIR__ . '/../../../../../../../library/Icinga/Application/Icinga.php');
-require_once realpath(__DIR__ . '/../../../../../../../library/Icinga/Web/Form/Element/DateTimePicker.php');
-require_once realpath(__DIR__ . '/../../../../../../../library/Icinga/Util/ConfigAwareFactory.php');
-require_once realpath(__DIR__ . '/../../../../../../../library/Icinga/Util/DateTimeFactory.php');
+require_once realpath(__DIR__ . '/../../../../../../../library/Icinga/Test/BaseTestCase.php');
+require_once realpath(BaseTestCase::$libDir . '/Application/Icinga.php');
+require_once realpath(BaseTestCase::$libDir . '/Web/Form/Element/DateTimePicker.php');
+require_once realpath(BaseTestCase::$libDir . '/Web/Form/Validator/DateTimeValidator.php');
+require_once realpath(BaseTestCase::$libDir . '/Util/ConfigAwareFactory.php');
+require_once realpath(BaseTestCase::$libDir . '/Util/DateTimeFactory.php');
 
 use \DateTimeZone;
-use \PHPUnit_Framework_TestCase;
+use Icinga\Form\Config\Authentication\BaseBackendForm;
 use \Icinga\Web\Form\Element\DateTimePicker;
 use \Icinga\Util\DateTimeFactory;
 
-class DateTimeTest extends PHPUnit_Framework_TestCase
+class DateTimeTest extends BaseTestCase
 {
     public function setUp()
     {