Initial import of koward.
authorGunnar Wrobel <p@rdus.de>
Fri, 3 Apr 2009 10:16:35 +0000 (12:16 +0200)
committerGunnar Wrobel <p@rdus.de>
Fri, 3 Apr 2009 10:16:35 +0000 (12:16 +0200)
This application should replace the kolab-webadmin in the long run. It
is primarily intended as an LDAP database manager based on the
Kolab_Server library.

37 files changed:
koward/app/controllers/ApplicationController.php [new file with mode: 0644]
koward/app/controllers/CheckController.php [new file with mode: 0644]
koward/app/controllers/IndexController.php [new file with mode: 0644]
koward/app/controllers/ObjectController.php [new file with mode: 0644]
koward/app/views/Check/run.html.php [new file with mode: 0644]
koward/app/views/Check/show.html.php [new file with mode: 0644]
koward/app/views/Index/index.html.php [new file with mode: 0644]
koward/app/views/Modify/add.html.php [new file with mode: 0644]
koward/app/views/Object/delete.html.php [new file with mode: 0644]
koward/app/views/Object/edit.html.php [new file with mode: 0644]
koward/app/views/Object/listall.html.php [new file with mode: 0644]
koward/app/views/Object/view.html.php [new file with mode: 0644]
koward/app/views/shared/_header.html.php [new file with mode: 0644]
koward/app/views/shared/_menu.html.php [new file with mode: 0644]
koward/bin/bootstrap.php [new file with mode: 0644]
koward/config/attributes.php [new file with mode: 0644]
koward/config/conf.php [new file with mode: 0644]
koward/config/objects.php [new file with mode: 0644]
koward/config/routes.php [new file with mode: 0644]
koward/doc/QUESTIONS.txt [new file with mode: 0644]
koward/lib/Exception.php [new file with mode: 0644]
koward/lib/Form/Object.php [new file with mode: 0644]
koward/lib/Koward.php [new file with mode: 0644]
koward/lib/Test.php [new file with mode: 0644]
koward/lib/Test/AllTests.php [new file with mode: 0644]
koward/lib/Test/Renderer.php [new file with mode: 0644]
koward/lib/Test/Server/UserTest.php [new file with mode: 0644]
koward/lib/Test/Template/scenario.html.dist [new file with mode: 0644]
koward/lib/Test/Template/scenario_header.html.dist [new file with mode: 0644]
koward/lib/Test/Template/scenarios.html.dist [new file with mode: 0644]
koward/lib/Test/Template/step.html.dist [new file with mode: 0644]
koward/test/AllTests.php [new file with mode: 0644]
koward/test/KowardTest.php [new file with mode: 0644]
koward/test/TestInit.php [new file with mode: 0644]
koward/themes/graphics/favicon.ico [new file with mode: 0644]
koward/themes/graphics/query.png [new file with mode: 0644]
koward/themes/kolab/screen.css [new file with mode: 0644]

diff --git a/koward/app/controllers/ApplicationController.php b/koward/app/controllers/ApplicationController.php
new file mode 100644 (file)
index 0000000..55cfd47
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+
+class Koward_ApplicationController extends Horde_Controller_Base
+{
+    protected function _initializeApplication()
+    {
+        $this->koward = Koward_Koward::singleton();
+
+        $this->types = array_keys($this->koward->objects);
+        if (empty($this->types)) {
+            throw new KowardException('No object types have been configured!');
+        }
+
+        $this->menu = $this->getMenu();
+
+        $this->theme = isset($this->koward->conf['koward']['theme']) ? $this->koward->conf['koward']['theme'] : 'koward';
+    }
+
+    /**
+     * Builds Koward's list of menu items.
+     */
+    public function getMenu()
+    {
+        global $registry;
+
+        require_once 'Horde/Menu.php';
+        $menu = new Menu();
+
+        $menu->add($this->urlFor(array('controller' => 'object', 'action' => 'listall')),
+                   _("_Objects"), 'user.png', $registry->getImageDir('horde'));
+        $menu->add($this->urlFor(array('controller' => 'object', 'action' => 'edit')),
+                   _("_Add"), 'plus.png', $registry->getImageDir('horde'));
+        $menu->add(Horde::applicationUrl('search'), _("_Search"), 'search.png', $registry->getImageDir('horde'));
+        $menu->add(Horde::applicationUrl('Queries'), _("_Queries"), 'query.png', $registry->getImageDir('koward'));
+        $menu->add($this->urlFor(array('controller' => 'check', 'action' => 'show')),
+                   _("_Test"), 'problem.png', $registry->getImageDir('horde'));
+
+        return $menu;
+    }
+}
diff --git a/koward/app/controllers/CheckController.php b/koward/app/controllers/CheckController.php
new file mode 100644 (file)
index 0000000..39bf83e
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @package Koward
+ */
+
+// @TODO Clean up
+require_once dirname(__FILE__) . '/ApplicationController.php';
+
+/**
+ * @package Koward
+ */
+class CheckController extends Koward_ApplicationController
+{
+
+    protected function _initializeApplication()
+    {
+        parent::_initializeApplication();
+
+        $this->suite = Koward_Test_AllTests::suite();
+    }
+
+    public function show()
+    {
+        $this->list = array();
+
+        $this->list[0] = Horde::link(
+            $this->urlFor(array('controller' => 'check',
+                                'action' => 'run',
+                                'id' => 'all')),
+            _("All tests")) . _("All tests") . '</a>';
+
+        $this->list[1] = '';
+
+        for ($i = 0; $i < $this->suite->count(); $i++) {
+            $class_name = $this->suite->testAt($i)->getName();
+            $this->list[$i + 2] = Horde::link(
+                $this->urlFor(array('controller' => 'check',
+                                    'action' => 'run',
+                                    'id' => $i + 1)),
+                $class_name) . $class_name . '</a>';
+        }
+    }
+
+    public function run()
+    {
+        
+        if ($this->params['id'] == 'all') {
+            $this->test = $this->suite;
+        } else {
+            $id = (int) $this->params['id'];
+            if (!empty($id)) {
+                $this->test = $this->suite->testAt($id - 1);
+            } else {
+                $this->test = null;
+                $this->koward->notification->push(_("You selected no test!"));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/koward/app/controllers/IndexController.php b/koward/app/controllers/IndexController.php
new file mode 100644 (file)
index 0000000..40e2c77
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+/**
+ * @package Koward
+ */
+
+// @TODO Clean up
+require_once dirname(__FILE__) . '/ApplicationController.php';
+
+/**
+ * @package Koward
+ */
+class IndexController extends Koward_ApplicationController
+{
+    protected $welcome;
+
+    public function index()
+    {
+        $this->title = _("Index");
+        $this->welcome = _("Welcome to the Koward administration interface");
+    }
+}
\ No newline at end of file
diff --git a/koward/app/controllers/ObjectController.php b/koward/app/controllers/ObjectController.php
new file mode 100644 (file)
index 0000000..f76f32d
--- /dev/null
@@ -0,0 +1,144 @@
+<?php
+/**
+ * @package Koward
+ */
+
+// @TODO Clean up
+require_once dirname(__FILE__) . '/ApplicationController.php';
+
+/**
+ * @package Koward
+ */
+class ObjectController extends Koward_ApplicationController
+{
+
+    public function listall()
+    {
+        require_once 'Horde/UI/Tabs.php';
+        require_once 'Horde/Variables.php';
+        require_once 'Horde/Util.php';
+
+        $this->object_type = $this->params->get('id', $this->types[0]);
+
+        if (isset($this->koward->objects[$this->object_type])) {
+            $this->attributes = $this->koward->objects[$this->object_type]['attributes'];
+            $params = array('attributes' => array_keys($this->attributes));
+            $this->objectlist = $this->koward->server->listHash($this->object_type,
+                                                               $params);
+            foreach ($this->objectlist as $uid => $info) {
+                $this->objectlist[$uid]['edit_url'] = Horde::link(
+                    $this->urlFor(array('controller' => 'object', 
+                                        'action' => 'edit',
+                                        'id' => $uid)),
+                    _("Edit")) . Horde::img('edit.png', _("Edit"), '',
+                                            $GLOBALS['registry']->getImageDir('horde'))
+                    . '</a>';
+                $this->objectlist[$uid]['delete_url'] = Horde::link(
+                    $this->urlFor(array('controller' => 'object', 
+                                        'action' => 'delete',
+                                        'id' => $uid)),
+                    _("Delete")) . Horde::img('delete.png', _("Delete"), '',
+                                              $GLOBALS['registry']->getImageDir('horde'))
+                    . '</a>';
+                $this->objectlist[$uid]['view_url'] = Horde::link(
+                    $this->urlFor(array('controller' => 'object', 
+                                        'action' => 'view',
+                                        'id' => $uid)), _("View"));
+            }
+        } else {
+            $this->objectlist = 'Unkown object type.';
+        }
+        $this->tabs = new Horde_UI_Tabs(null, Variables::getDefaultVariables());
+        foreach ($this->koward->objects as $key => $configuration) {
+            $this->tabs->addTab($configuration['list_label'],
+                                $this->urlFor(array('controller' => 'object', 
+                                                    'action' => 'listall',
+                                                    'id' => $key)),
+                                $key);
+        }
+
+        $this->render();
+    }
+
+    public function delete()
+    {
+        try {
+            if (empty($this->params->id)) {
+                $this->koward->notification->push(_("The object that should be deleted has not been specified."),
+                                                 'horde.error');
+            } else {
+                $this->object = $this->koward->getObject($this->params->id);
+                if (empty($this->params->submit)) {
+                    $this->token  = $this->koward->getRequestToken('object.delete');
+                } else {
+                    $this->koward->checkRequestToken('object.delete', $this->params->token);
+                    $this->object->delete();
+                    $this->koward->notification->push(sprintf(_("Successfully deleted the object \"%s\""),
+                                                             $this->params->id),
+                                                     'horde.message');
+                    header('Location: ' . $this->urlFor(array('controller' => 'object', 
+                                                              'action' => 'listall',
+                                                              'id' => get_class($this->object))));
+                    exit;
+                }
+            }
+        } catch (Exception $e) {
+            $this->koward->notification->push($e->getMessage(), 'horde.error');
+        }
+
+        $this->render();
+    }
+
+    public function view()
+    {
+        try {
+            if (empty($this->params->id)) {
+                $this->koward->notification->push(_("The object that should be viewed has not been specified."),
+                                                 'horde.error');
+            } else {
+                $this->object = $this->koward->getObject($this->params->id);
+
+                require_once 'Horde/Variables.php';
+                $this->vars = Variables::getDefaultVariables();
+                $this->form = new Koward_Form_Object($this->vars, $this->object,
+                                                    array('title' => _("View object")));
+            }
+        } catch (Exception $e) {
+            $this->koward->notification->push($e->getMessage(), 'horde.error');
+        }
+
+        $this->render();
+    }
+
+    public function edit()
+    {
+        try {
+            if (empty($this->params->id)) {
+                $this->object = null;
+            } else {
+                $this->object = $this->koward->getObject($this->params->id);
+            }
+
+            require_once 'Horde/Variables.php';
+            $this->vars = Variables::getDefaultVariables();
+            $this->form = new Koward_Form_Object($this->vars, $this->object);
+
+            if ($this->form->validate()) {
+                $object = $this->form->execute();
+
+                header('Location: ' . $this->urlFor(array('controller' => 'object', 
+                                                          'action' => 'view',
+                                                          'id' => $object->get(Horde_Koward_Server_Object::ATTRIBUTE_UID))));
+                exit;
+            }
+        } catch (Exception $e) {
+            $this->koward->notification->push($e->getMessage(), 'horde.error');
+        }
+
+        $this->post = $this->urlFor(array('controller' => 'object', 
+                                          'action' => 'edit',
+                                          'id' => $this->params->id));
+
+        $this->render();
+    }
+}
\ No newline at end of file
diff --git a/koward/app/views/Check/run.html.php b/koward/app/views/Check/run.html.php
new file mode 100644 (file)
index 0000000..ea945e8
--- /dev/null
@@ -0,0 +1,10 @@
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<?php
+if (!empty($this->test)) {
+    ob_start();
+    $listener = new Koward_Test_Renderer();
+    PHPUnit_TextUI_TestRunner::run($this->test, array('listeners' => array($listener)));
+    echo ob_get_clean();
+}
\ No newline at end of file
diff --git a/koward/app/views/Check/show.html.php b/koward/app/views/Check/show.html.php
new file mode 100644 (file)
index 0000000..f58908f
--- /dev/null
@@ -0,0 +1,9 @@
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<?php
+
+foreach ($this->list as $test) {
+    echo $test;
+    echo '<br/>';
+}
\ No newline at end of file
diff --git a/koward/app/views/Index/index.html.php b/koward/app/views/Index/index.html.php
new file mode 100644 (file)
index 0000000..0696b72
--- /dev/null
@@ -0,0 +1,6 @@
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<div class="contenttext">
+   <h1><?= $this->welcome ?></h1>
+</div>
diff --git a/koward/app/views/Modify/add.html.php b/koward/app/views/Modify/add.html.php
new file mode 100644 (file)
index 0000000..fb15bbe
--- /dev/null
@@ -0,0 +1,6 @@
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<?php
+$this->form->renderActive(new Horde_Form_Renderer(), $vars, 'modify', 'post');
+
diff --git a/koward/app/views/Object/delete.html.php b/koward/app/views/Object/delete.html.php
new file mode 100644 (file)
index 0000000..055e78c
--- /dev/null
@@ -0,0 +1,2 @@
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
diff --git a/koward/app/views/Object/edit.html.php b/koward/app/views/Object/edit.html.php
new file mode 100644 (file)
index 0000000..5185924
--- /dev/null
@@ -0,0 +1,4 @@
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+<?= $this->form->renderActive(new Horde_Form_Renderer(), $this->vars,
+                              $this->post, 'post'); ?>
\ No newline at end of file
diff --git a/koward/app/views/Object/listall.html.php b/koward/app/views/Object/listall.html.php
new file mode 100644 (file)
index 0000000..d53aa87
--- /dev/null
@@ -0,0 +1,37 @@
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+
+<?= $this->tabs->render($this->object_type); ?>
+
+<table cellspacing="0" width="100%" class="linedRow">
+ <thead>
+  <tr>
+   <th class="item" width="1%"><?php echo Horde::img('edit.png', _("Edit"), '', $GLOBALS['registry']->getImageDir('horde')) ?></th>
+   <th class="item" width="1%"><?php echo Horde::img('delete.png', _("Delete"), '', $GLOBALS['registry']->getImageDir('horde')) ?></th>
+   <?php foreach ($this->attributes as $attribute => $info): ?>
+     <th class="item leftAlign" width="<?php echo $info['width'] ?>%" nowrap="nowrap"><?= $info['title'] ?></th>
+   <?php endforeach; ?>
+  </tr>
+ </thead>
+ <tbody>
+  <?php foreach ($this->objectlist as $dn => $info): ?>
+  <tr>
+   <td>
+    <?= $info['edit_url'] ?>
+   </td> 
+   <td>
+    <?= $info['delete_url'] ?>
+   </td> 
+   <?php foreach ($this->attributes as $attribute => $ainfo): ?>
+   <td>
+   <?php if (!empty($ainfo['link_view'])): ?>
+   <?= $info['view_url'] . $this->escape($info[$attribute]) . '</a>'; ?>
+   <?php else: ?>
+    <?= $this->escape($info[$attribute]) ?>
+   <?php endif; ?>
+   </td> 
+   <?php endforeach; ?>
+  </tr> 
+  <?php endforeach; ?>
+ </tbody>
+</table>
diff --git a/koward/app/views/Object/view.html.php b/koward/app/views/Object/view.html.php
new file mode 100644 (file)
index 0000000..f261764
--- /dev/null
@@ -0,0 +1,3 @@
+<?= $this->renderPartial('header'); ?>
+<?= $this->renderPartial('menu'); ?>
+<?= $this->form->renderInactive(new Horde_Form_Renderer(), $this->vars); ?>
\ No newline at end of file
diff --git a/koward/app/views/shared/_header.html.php b/koward/app/views/shared/_header.html.php
new file mode 100644 (file)
index 0000000..dc72ba8
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+if (isset($language)) {
+    header('Content-type: text/html; charset=' . NLS::getCharset());
+    header('Vary: Accept-Language');
+}
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+Koward - The Kolab warden
+
+Copyright
+
+2004 - 2009 Klarälvdalens Datakonsult AB
+2009        The Horde Project
+
+Koward is under the GPL. GNU Public License: http://www.fsf.org/copyleft/gpl.html -->
+
+<?php echo !empty($language) ? '<html lang="' . strtr($language, '_', '-') . '">' : '<html>' ?>
+<head>
+<?php
+
+global $registry;
+
+$page_title = $registry->get('name');
+$page_title .= !empty($this->title) ? ' :: ' . $this->title : '';
+
+Horde::includeScriptFiles();
+?>
+<title><?php echo htmlspecialchars($page_title) ?></title>
+<link href="<?php echo $GLOBALS['registry']->getImageDir()?>/favicon.ico" rel="SHORTCUT ICON" />
+
+<?php echo Horde::stylesheetLink('koward', empty($this->print_view) ? $this->theme : 'print') ?>
+
+</head>
+
+<body>
diff --git a/koward/app/views/shared/_menu.html.php b/koward/app/views/shared/_menu.html.php
new file mode 100644 (file)
index 0000000..3be3269
--- /dev/null
@@ -0,0 +1,5 @@
+<div id="menu">
+ <?= $this->menu->render(); ?>
+</div>
+<?php $this->koward->notification->notify(array('listeners' => 'status')) ?>
+
diff --git a/koward/bin/bootstrap.php b/koward/bin/bootstrap.php
new file mode 100644 (file)
index 0000000..8003cab
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+define('AUTH_HANDLER', true);
+
+$options = array(
+    new Horde_Argv_Option('-n', '--not-defined', array('type' => 'int')),
+);
+$parser = new Horde_Argv_Parser(array('optionList' => $options));
+list($opts, $tags) = $parser->parseArgs();
+
+if (!$opts->not_defined) {
+    throw new InvalidArgumentException('');
+}
+
+exit(0);
diff --git a/koward/config/attributes.php b/koward/config/attributes.php
new file mode 100644 (file)
index 0000000..3a49086
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+$attributes['givenName'] = array(
+    'label' => _("First Name"),
+    'type' => 'text',
+    'required' => true,
+    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
+$attributes['sn'] = array(
+    'label' => _("Last Name"),
+    'type' => 'text',
+    'required' => true,
+    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
+$attributes['mail'] = array(
+    'label' => _("Mail address"),
+    'type' => 'text',
+    'required' => true,
+    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
+$attributes['uid'] = array(
+    'label' => _("User ID"),
+    'type' => 'text',
+    'required' => true,
+    'params' => array('regex' => '', 'size' => 40, 'maxlength' => 255)
+);
diff --git a/koward/config/conf.php b/koward/config/conf.php
new file mode 100644 (file)
index 0000000..656621c
--- /dev/null
@@ -0,0 +1,3 @@
+<?php
+
+$conf['koward']['theme'] = 'silver';
diff --git a/koward/config/objects.php b/koward/config/objects.php
new file mode 100644 (file)
index 0000000..b394cd2
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+
+$objects['Horde_Kolab_Server_Object'] = array(
+    'label'       => _("Object"),
+    'list_label'  => _("Objects"),
+    'attributes'  => array(
+        'id' => array(
+            'title' => _("Object id"),
+            'width' => 80,
+            'link_view'=> true,
+        ),
+    ),
+);
+
+$objects['Horde_Kolab_Server_Object_user'] = array(
+    'label'       => _("User"),
+    'list_label'  => _("Users"),
+    'attributes'  => array(
+        'sn' => array(
+            'title' => _("Last name"),
+            'width' => 20,
+        ),
+        'givenName' => array(
+            'title' => _("First name"),
+            'width' => 20,
+        ),
+        'mail' => array(
+            'title' => _("E-mail"),
+            'width' => 20,
+            'link_view'=> true,
+        ),
+        'uid' => array(
+            'title' => _("User ID"),
+            'width' => 20,
+        ),
+    ),
+);
+
+$objects['Horde_Kolab_Server_Object_administrator'] = array(
+    'label'       => _("Administrator"),
+    'list_label'  => _("Administrators"),
+    'attributes'  => array(
+    ),
+);
diff --git a/koward/config/routes.php b/koward/config/routes.php
new file mode 100644 (file)
index 0000000..1043478
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+$mapper->connect('index', array('controller' => 'index'));
+$mapper->connect('index.php', array('controller' => 'index'));
+
+$mapper->connect('check/:action/:id', array('controller' => 'check', 'action' => 'show'));
+$mapper->connect(':controller/:action/:id', array('controller' => 'object'));
+
+// Local route overrides
+if (file_exists(dirname(__FILE__) . '/routes.local.php')) {
+    include dirname(__FILE__) . '/routes.local.php';
+}
diff --git a/koward/doc/QUESTIONS.txt b/koward/doc/QUESTIONS.txt
new file mode 100644 (file)
index 0000000..0955803
--- /dev/null
@@ -0,0 +1,5 @@
+Can we have mixed CLI and html views? If we can, will these be in a library install location?
+
+How to add translations?
+
+How to install via PEAR?
diff --git a/koward/lib/Exception.php b/koward/lib/Exception.php
new file mode 100644 (file)
index 0000000..3498db4
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+/**
+ * An application for managing a Kolab server.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Koward_Server
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward_Server
+ */
+
+/**
+ * This class provides the standard error class for the Koward application.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Kolab
+ * @package  Koward_Server
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward_Server
+ */
+class Koward_Exception extends Exception
+{
+}
diff --git a/koward/lib/Form/Object.php b/koward/lib/Form/Object.php
new file mode 100644 (file)
index 0000000..5a4a352
--- /dev/null
@@ -0,0 +1,118 @@
+<?php
+/**
+ * @package Koward
+ */
+
+/**
+ * @package Koward
+ */
+class Koward_Form_Object extends Horde_Form {
+
+    /**
+     * The link to the application driver.
+     *
+     * @var Koward_Koward
+     */
+    protected $koward;
+
+    public function __construct(&$vars, &$object, $params = array())
+    {
+        $this->koward = &Koward_Koward::singleton();
+
+        $this->object = &$object;
+
+        parent::Horde_Form($vars);
+
+        if (empty($this->object)) {
+            $title = _("Add Object");
+            $this->setButtons(_("Add"));
+
+            foreach ($this->koward->objects as $key => $config) {
+                $options[$key] = $config['label'];
+            }
+            
+            $v = &$this->addVariable(_("Choose an object type"), 'type', 'enum', true, false, null, array($options, true));
+            $action = Horde_Form_Action::factory('submit');
+            $v->setAction($action);
+            $v->setOption('trackchange', true);
+            if (is_null($vars->get('formname')) &&
+                $vars->get($v->getVarName()) != $vars->get('__old_' . $v->getVarName())) {
+                $this->koward->notification->push(sprintf(_("Selected object type \"%s\"."), $object_conf[$vars->get('type')]['label']), 'horde.message');
+            }
+        } else {
+            $title = _("Edit Object");
+            $type = get_class($this->object);
+            if (!$this->isSubmitted()) {
+                $vars->set('type', $type);
+                $keys = array_keys($this->koward->objects[$type]['attributes']);
+                $vars->set('object', $this->object->toHash($keys));
+                $this->setButtons(_("Edit"));
+            }
+        }
+
+        if (isset($params['title'])) {
+            $title = $params['title'];
+        }
+
+        $this->setTitle($title);
+
+        $type = $vars->get('type');
+        if (isset($type)) {
+            $this->_addFields($this->koward->objects[$type]);
+        }
+    }
+
+    /**
+     * Set up the Horde_Form fields for the attributes of this object type.
+     */
+    function _addFields($config)
+    {
+        // Now run through and add the form variables.
+        $fields = isset($config['attributes']) ? $config['attributes'] : array();
+        $tabs   = isset($config['tabs']) ? $config['tabs'] : array('' => $fields);
+
+        foreach ($tabs as $tab => $tab_fields) {
+            if (!empty($tab)) {
+                $this->setSection($tab, $tab);
+            }
+            foreach ($tab_fields as $key => $field) {
+                if (!in_array($key, array_keys($fields)) ||
+                    !isset($this->koward->attributes[$key])) {
+                    continue;
+                }
+
+                $attribute = $this->koward->attributes[$key];
+                $params = isset($attribute['params']) ? $attribute['params'] : array();
+                $desc = isset($attribute['desc']) ? $attribute['desc'] : null;
+
+                $readonly = isset($attribute['readonly']) ? $attribute['readonly'] : null;
+                $v = &$this->addVariable($attribute['label'], 'object[' . $key . ']', $attribute['type'], $attribute['required'], $readonly, $desc, $params);
+            }
+
+            if (isset($attribute['default'])) {
+                $v->setDefault($attribute['default']);
+            }
+        }
+    }
+
+    function &execute()
+    {
+        $this->getInfo($this->_vars, $info);
+        if (isset($info['object'])) {
+            if (empty($this->object)) {
+                if (isset($info['type'])) {
+                    $object = $this->koward->server->add(array_merge(array('type' => $info['type']),
+                                                                 $info['object']));
+                    $this->koward->notification->push(_("Successfully added the object."),
+                                                     'horde.message');
+                    return $object;
+                }
+            } else {
+                $this->object->save($info['object']);
+                $this->koward->notification->push(_("Successfully updated the object."),
+                                                 'horde.message');
+                return $this->object;
+            }
+        }
+    }
+}
diff --git a/koward/lib/Koward.php b/koward/lib/Koward.php
new file mode 100644 (file)
index 0000000..744eea6
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+/**
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Gunnar Wrobel <p@rdus.de>
+ * @license  http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
+ * @category Kolab
+ * @package  Koward
+ */
+
+class Koward_Koward {
+
+    /**
+     * The singleton instance.
+     *
+     * @var Koward_Koward
+     */
+    static protected $instance = null;
+
+    public $objectconf;
+
+    public function __construct()
+    {
+        require_once 'Horde/Notification.php';
+        require_once 'Horde/Registry.php';
+
+        $this->notification = Notification::singleton();
+        $this->registry     = Registry::singleton();
+
+        $result = $this->registry->pushApp('koward', false);
+        if ($result instanceOf PEAR_Error) {
+            $this->notification->push($result);
+        }
+
+        $this->conf       = Horde::loadConfiguration('conf.php', 'conf');
+        $this->objects    = Horde::loadConfiguration('objects.php', 'objects');
+        $this->attributes = Horde::loadConfiguration('attributes.php', 'attributes');
+        $this->server     = Horde_Kolab_Server::singleton();
+    }
+
+    /**
+     * Get a token for protecting a form.
+     *
+     * @param string $seed  TODO
+     *
+     * @return  TODO
+     */
+    static public function getRequestToken($seed)
+    {
+        $token = Horde_Token::generateId($seed);
+        $_SESSION['horde_form_secrets'][$token] = time();
+        return $token;
+    }
+
+    /**
+     * Check if a token for a form is valid.
+     *
+     * @param string $seed   TODO
+     * @param string $token  TODO
+     *
+     * @throws Horde_Exception
+     */
+    static public function checkRequestToken($seed, $token)
+    {
+        if (empty($_SESSION['horde_form_secrets'][$token])) {
+            throw new Horde_Exception(_("We cannot verify that this request was really sent by you. It could be a malicious request. If you intended to perform this action, you can retry it now."));
+        }
+
+        if ($_SESSION['horde_form_secrets'][$token] + $GLOBALS['conf']['server']['token_lifetime'] < time()) {
+            throw new Horde_Exception(sprintf(_("This request cannot be completed because the link you followed or the form you submitted was only valid for %d minutes. Please try again now."), round($GLOBALS['conf']['server']['token_lifetime'] / 60)));
+        }
+    }
+
+    public function getObject($uid)
+    {
+        return $this->server->fetch($uid);
+    }
+
+    static public function singleton()
+    {
+        if (!isset(self::$instance)) {
+            self::$instance = new Koward_Koward();
+        }
+
+        return self::$instance;
+    }
+}
\ No newline at end of file
diff --git a/koward/lib/Test.php b/koward/lib/Test.php
new file mode 100644 (file)
index 0000000..62b9379
--- /dev/null
@@ -0,0 +1,173 @@
+<?php
+/**
+ * Base for PHPUnit scenarios.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward
+ */
+
+/**
+ * Base for PHPUnit scenarios.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward
+ */
+class Koward_Test extends Horde_Kolab_Test_Storage
+{
+    /**
+     * Prepare the configuration.
+     *
+     * @return NULL
+     */
+    public function prepareConfiguration()
+    {
+        $fh = fopen(HORDE_BASE . '/config/conf.php', 'w');
+        $data = <<<EOD
+\$conf['use_ssl'] = 2;
+\$conf['server']['name'] = \$_SERVER['SERVER_NAME'];
+\$conf['server']['port'] = \$_SERVER['SERVER_PORT'];
+\$conf['debug_level'] = E_ALL;
+\$conf['umask'] = 077;
+\$conf['compress_pages'] = true;
+\$conf['menu']['always'] = false;
+\$conf['portal']['fixed_blocks'] = array();
+\$conf['imsp']['enabled'] = false;
+
+/** Additional config variables required for a clean Horde setup */
+\$conf['session']['use_only_cookies'] = false;
+\$conf['session']['timeout'] = 0;
+\$conf['cookie']['path'] = '/';
+\$conf['cookie']['domain'] = \$_SERVER['SERVER_NAME'];
+\$conf['use_ssl'] = false;
+\$conf['session']['cache_limiter'] = 'nocache';
+\$conf['session']['name'] = 'Horde';
+\$conf['log']['enabled'] = false;
+\$conf['prefs']['driver'] = 'session';
+\$conf['auth']['driver'] = 'kolab';
+\$conf['share']['driver'] = 'kolab';
+\$conf['server']['token_lifetime'] = 3600;
+\$conf['debug_level'] = E_ALL;
+
+/** Make the share driver happy */
+\$conf['kolab']['enabled'] = true;
+
+/** Ensure we still use the LDAP test driver */
+\$conf['kolab']['server']['driver'] = 'test';
+
+/** Ensure that we do not trigger on folder update */
+\$conf['kolab']['no_triggering'] = true;
+
+/** Storage location for the free/busy system */
+\$conf['fb']['cache_dir']             = '/tmp';
+\$conf['kolab']['freebusy']['server'] = 'https://fb.example.org/freebusy';
+
+/** Setup the virtual file system for Kolab */
+\$conf['vfs']['params']['all_folders'] = true;
+\$conf['vfs']['type'] = 'kolab';
+
+\$conf['kolab']['ldap']['phpdn'] = null;
+\$conf['fb']['use_acls'] = true;
+EOD;
+        fwrite($fh, "<?php\n" . $data);
+        fclose($fh);
+    }
+
+    /**
+     * Prepare the registry.
+     *
+     * @return NULL
+     */
+    public function prepareRegistry()
+    {
+        $fh = fopen(HORDE_BASE . '/config/registry.php', 'w');
+        $data = <<<EOD
+\$this->applications['horde'] = array(
+    'fileroot' => dirname(__FILE__) . '/..',
+    'webroot' => '/',
+    'initial_page' => 'login.php',
+    'name' => _("Horde"),
+    'status' => 'active',
+    'templates' => dirname(__FILE__) . '/../templates',
+    'provides' => 'horde',
+);
+
+\$this->applications['koward'] = array(
+    'fileroot' => KOWARD_BASE,
+    'webroot' => \$this->applications['horde']['webroot'] . '/koward',
+    'name' => _("Koward"),
+    'status' => 'active',
+    'initial_page' => 'index.php',
+);
+EOD;
+        fwrite($fh, "<?php\n" . $data);
+        fclose($fh);
+        if (!file_exists(HORDE_BASE . '/config/registry.d')) {
+            mkdir(HORDE_BASE . '/config/registry.d');
+        }
+    }
+
+    /**
+     * Handle a "given" step.
+     *
+     * @param array  &$world    Joined "world" of variables.
+     * @param string $action    The description of the step.
+     * @param array  $arguments Additional arguments to the step.
+     *
+     * @return mixed The outcome of the step.
+     */
+    public function runGiven(&$world, $action, $arguments)
+    {
+        switch($action) {
+        default:
+            return parent::runGiven($world, $action, $arguments);
+        }
+    }
+
+    /**
+     * Handle a "when" step.
+     *
+     * @param array  &$world    Joined "world" of variables.
+     * @param string $action    The description of the step.
+     * @param array  $arguments Additional arguments to the step.
+     *
+     * @return mixed The outcome of the step.
+     */
+    public function runWhen(&$world, $action, $arguments)
+    {
+        switch($action) {
+        default:
+            return parent::runWhen($world, $action, $arguments);
+        }
+    }
+
+    /**
+     * Handle a "then" step.
+     *
+     * @param array  &$world    Joined "world" of variables.
+     * @param string $action    The description of the step.
+     * @param array  $arguments Additional arguments to the step.
+     *
+     * @return mixed The outcome of the step.
+     */
+    public function runThen(&$world, $action, $arguments)
+    {
+        switch($action) {
+        default:
+            return parent::runThen($world, $action, $arguments);
+        }
+    }
+
+}
diff --git a/koward/lib/Test/AllTests.php b/koward/lib/Test/AllTests.php
new file mode 100644 (file)
index 0000000..0346a55
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+/**
+ * All server tests for the Kolab server.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * The Autoloader allows us to omit "require/include" statements.
+ */
+require_once 'Horde/Autoloader.php';
+
+/**
+ * Combine the tests for this package.
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Kolab
+ * @package  Kolab_Server
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Kolab_Server
+ */
+class Koward_Test_AllTests
+{
+
+    /**
+     * Main entry point for running the suite.
+     *
+     * @return NULL
+     */
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    /**
+     * Collect the unit tests of this directory into a new suite.
+     *
+     * @return PHPUnit_Framework_TestSuite The test suite.
+     */
+    public static function suite()
+    {
+        // Catch strict standards
+        // FIXME: This does not work yet, as we still have a number of
+        //        static methods in basic Horde libraries that are not
+        //        declared as such.
+        //error_reporting(E_ALL | E_STRICT);
+
+        $suite = new PHPUnit_Framework_TestSuite('Kolab server test suite');
+
+        $basedir    = dirname(__FILE__);
+        $baseregexp = preg_quote($basedir . DIRECTORY_SEPARATOR, '/');
+
+        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file) {
+            if ($file->isFile() && preg_match('/Test.php$/', $file->getFilename())) {
+                $pathname = $file->getPathname();
+                require $pathname;
+
+                $class = str_replace(DIRECTORY_SEPARATOR, '_',
+                                     preg_replace("/^$baseregexp(.*)\.php/", '\\1', $pathname));
+                $suite->addTestSuite('Koward_Test_' . $class);
+            }
+        }
+
+        return $suite;
+    }
+
+}
diff --git a/koward/lib/Test/Renderer.php b/koward/lib/Test/Renderer.php
new file mode 100644 (file)
index 0000000..e8308aa
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+
+class Koward_Test_Renderer extends PHPUnit_Extensions_Story_ResultPrinter_HTML
+{
+    /**
+     * Constructor.
+     *
+     * @param  mixed   $out
+     * @throws InvalidArgumentException
+     */
+    public function __construct($out = NULL)
+    {
+        parent::__construct($out);
+
+        $this->templatePath = sprintf(
+          '%s%sTemplate%s',
+
+          dirname(__FILE__),
+          DIRECTORY_SEPARATOR,
+          DIRECTORY_SEPARATOR
+        );
+    }
+
+    /**
+     * @param  string $buffer
+     */
+    public function write($buffer)
+    {
+        if ($this->out !== NULL) {
+            fwrite($this->out, $buffer);
+
+            if ($this->autoFlush) {
+                $this->incrementalFlush();
+            }
+        } else {
+
+            print $buffer;
+
+            if ($this->autoFlush) {
+                $this->incrementalFlush();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/koward/lib/Test/Server/UserTest.php b/koward/lib/Test/Server/UserTest.php
new file mode 100644 (file)
index 0000000..d2f0559
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Test the user object.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward
+ */
+
+/**
+ * Test the user object.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward
+ */
+class Koward_Test_Server_UserTest extends Horde_Kolab_Test_Server {
+
+    /**
+     * Test listing users if there are no users.
+     *
+     * @scenario
+     *
+     * @return NULL
+     */
+    public function listingUsersOnEmptyServer()
+    {
+        $this->given('the current Kolab server')
+            ->when('listing all users')
+            ->then('the list is an empty array');
+    }
+}
diff --git a/koward/lib/Test/Template/scenario.html.dist b/koward/lib/Test/Template/scenario.html.dist
new file mode 100644 (file)
index 0000000..caa149a
--- /dev/null
@@ -0,0 +1,13 @@
+   <tr>
+    <td>
+     <p class="{scenarioStatus}" onclick="showHide('{id}', this)">[+] {name}</p>
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <table border="0" width="100%" class="{scenarioStatus} scenarioStepsTable" id="stepContainer{id}">
+{steps}
+     </table>
+    </td>
+   </tr>
+
diff --git a/koward/lib/Test/Template/scenario_header.html.dist b/koward/lib/Test/Template/scenario_header.html.dist
new file mode 100644 (file)
index 0000000..7b205d1
--- /dev/null
@@ -0,0 +1,6 @@
+   <tr>
+    <td>
+     <p class="header">{name}</p>
+    </td>
+   </tr>
+
diff --git a/koward/lib/Test/Template/scenarios.html.dist b/koward/lib/Test/Template/scenarios.html.dist
new file mode 100644 (file)
index 0000000..1037cfb
--- /dev/null
@@ -0,0 +1,54 @@
+  <style type ="text/css">
+  .scenarioSuccess { color: green; }
+  .scenario { color: black; }
+  .scenarioFailed { color: red; }
+  .scenarioSkipped { color: teal; }
+  .scenarioIncomplete { color: gray; }
+  .scenarioStepsTable { margin-left: 10px; display: none; }
+  .stepName { }
+  </style>
+
+  <script type="text/javascript">
+  function showHide(nodeId, linkObj)
+  {
+    var subObj = document.getElementById('stepContainer' + nodeId);
+
+    if (linkObj.innerHTML.indexOf('+')>0) {
+      linkObj.innerHTML = linkObj.innerHTML.replace('+','-');
+      subObj.style.display='block';
+      subObj.style.width = '100%';
+    } else {
+      linkObj.innerHTML = linkObj.innerHTML.replace('-','+');
+      subObj.style.display='none';
+    }
+  }
+  </script>
+
+  <table border="0" width="100%" style="margin: 20 px">
+{scenarios}
+   <tr>
+    <td>
+     <p style="margin-top: 20px;" id="Summary" onclick="showHide('Summary', this)">[+] Summary:</p>
+     <div style="margin-left: 10px; display:none" id="stepContainerSummary">
+      <table border="0">
+       <tr>
+        <td width="250" class="scenarioSuccess">Successful scenarios:</td>
+        <td class="scenarioSuccessValue">{successfulScenarios}</td>
+       </tr>
+       <tr>
+        <td class="scenarioFailed">Failed scenarios:</td>
+        <td class="scenarioFailedValue">{failedScenarios}</td>
+       </tr>
+       <tr>
+        <td class="scenarioSkipped">Skipped scenarios:</td>
+        <td class="scenarioSkippedValue">{skippedScenarios}</td>
+       </tr>
+       <tr>
+        <td class="scenarioIncomplete">Incomplete scenarios:</td>
+        <td class="scenarioIncompleteValue">{incompleteScenarios}</td>
+       </tr>
+      </table>
+     </div>
+    </td>
+   </tr>
+  </table>
diff --git a/koward/lib/Test/Template/step.html.dist b/koward/lib/Test/Template/step.html.dist
new file mode 100644 (file)
index 0000000..bcdce3f
--- /dev/null
@@ -0,0 +1,6 @@
+      <tr>
+       <td width="60">{text}</td>
+       <td class="stepName">{action}</td>
+       <td>&nbsp;</td>
+      </tr>
+
diff --git a/koward/test/AllTests.php b/koward/test/AllTests.php
new file mode 100644 (file)
index 0000000..3d1f3a7
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/**
+ * All tests for the Koward application.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Koward_AllTests::main');
+}
+
+/**
+ * Initialize testing for this application.
+ */
+require_once 'TestInit.php';
+
+/**
+ * Combine the tests for this package.
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward
+ */
+class Koward_AllTests
+{
+    /**
+     * Main entry point for running the suite.
+     *
+     * @return NULL
+     */
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    /**
+     * Collect the unit tests of this directory into a new suite.
+     *
+     * @return PHPUnit_Framework_TestSuite The test suite.
+     */
+    public static function suite()
+    {
+        // Catch strict standards
+        error_reporting(E_ALL | E_STRICT);
+
+        // Build the suite
+        $suite = new PHPUnit_Framework_TestSuite('Koward');
+
+        $basedir = dirname(__FILE__);
+        $baseregexp = preg_quote($basedir . DIRECTORY_SEPARATOR, '/');
+
+        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file) {
+            if ($file->isFile() && preg_match('/Test.php$/', $file->getFilename())) {
+                $pathname = $file->getPathname();
+                require $pathname;
+
+                $class = str_replace(DIRECTORY_SEPARATOR, '_',
+                                     preg_replace("/^$baseregexp(.*)\.php/", '\\1', $pathname));
+                $suite->addTestSuite('Koward_' . $class);
+            }
+        }
+
+        return $suite;
+    }
+
+}
+
+if (PHPUnit_MAIN_METHOD == 'Koward_AllTests::main') {
+    Koward_AllTests::main();
+}
diff --git a/koward/test/KowardTest.php b/koward/test/KowardTest.php
new file mode 100644 (file)
index 0000000..4b4abf5
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+/**
+ * Test the user object.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward
+ */
+
+/**
+ * Initialize testing for this application.
+ */
+require_once 'TestInit.php';
+
+/**
+ * Test the user object.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward
+ */
+class Koward_KowardTest extends Koward_Test
+{
+    /**
+     * Set up testing.
+     *
+     * @return NULL
+     */
+    protected function setUp()
+    {
+        $world = $this->prepareBasicSetup();
+
+        $this->koward = Koward_Koward::singleton();
+    }
+
+    /**
+     * Verify that the Koward object ist initialized correctly.
+     *
+     * @return NULL
+     */
+    public function testSetup()
+    {
+        $this->assertType('Horde_Kolab_Server', $this->koward->server);
+    }
+
+    /**
+     * Verify that we can fetch objects from the Kolab server.
+     *
+     * @return NULL
+     */
+    public function testFetching()
+    {
+        $this->assertType('Horde_Kolab_Server_Object', $this->koward->getObject('cn=Gunnar Wrobel,dc=example,dc=org'));
+    }
+
+    /**
+     * Verify token processing mechanisms.
+     *
+     * @return NULL
+     */
+    public function testToken()
+    {
+        // Get the token.
+        $token = $this->koward->getRequestToken('test');
+        // Checking it should be fine.
+        $this->koward->checkRequestToken('test', $token);
+        // Now we set the token to a value that will be considered a timeout.
+        $_SESSION['horde_form_secrets'][$token] = time() - 100000;
+        try {
+            $this->koward->checkRequestToken('test', $token);
+            $this->fail('The rquest token is still valid which was not expected.');
+        } catch (Horde_Exception $e) {
+            $this->assertContains(_("This request cannot be completed because the link you followed or the form you submitted was only valid for"), $e->getMessage());
+        }
+        // Now we remove the token
+        unset($_SESSION['horde_form_secrets'][$token]);
+        try {
+            $this->koward->checkRequestToken('test', $token);
+            $this->fail('The rquest token is still valid which was not expected.');
+        } catch (Horde_Exception $e) {
+            $this->assertEquals(_("We cannot verify that this request was really sent by you. It could be a malicious request. If you intended to perform this action, you can retry it now."), $e->getMessage());
+        }
+    }
+}
diff --git a/koward/test/TestInit.php b/koward/test/TestInit.php
new file mode 100644 (file)
index 0000000..8091e44
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Initialize testing for this application.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Koward
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @license  http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link     http://pear.horde.org/index.php?package=Koward
+ */
+
+/**
+ * The Autoloader allows us to omit "require/include" statements.
+ */
+require_once 'Horde/Autoloader.php';
+
+if (!defined('KOWARD_BASE')) {
+    define('KOWARD_BASE', dirname(__FILE__) . '/../');
+}
+
+/* Set up the application class and controller loading */
+Horde_Autoloader::addClassPattern('/^Koward_/', KOWARD_BASE . '/lib/');
+Horde_Autoloader::addClassPattern('/^Koward_/', KOWARD_BASE . '/app/controllers/');
diff --git a/koward/themes/graphics/favicon.ico b/koward/themes/graphics/favicon.ico
new file mode 100644 (file)
index 0000000..0f8fa08
Binary files /dev/null and b/koward/themes/graphics/favicon.ico differ
diff --git a/koward/themes/graphics/query.png b/koward/themes/graphics/query.png
new file mode 100644 (file)
index 0000000..ef46d4a
Binary files /dev/null and b/koward/themes/graphics/query.png differ
diff --git a/koward/themes/kolab/screen.css b/koward/themes/kolab/screen.css
new file mode 100644 (file)
index 0000000..017e2a7
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+  Local variables:
+  buffer-file-coding-system: utf-8
+  End:
+*/
+body {
+  color: black;
+  background-color: #F8FCF8;
+  font-family: verdana,arial,helvetica,sans-serif;
+  font-size: 95%;
+  border: 0;
+  margin: 0;
+}
+a, a:visited {
+  font-family: verdana,arial,helvetica,sans-serif;
+}
+
+a { color: #001155; }
+a:hover { color: #113399; }
+
+#page {
+  background-repeat: no-repeat;
+  background-position: top right;
+}
+
+#topbar {
+  display:block;
+  background-color: #B0BCD0;
+  height: 70px;
+  clear: both;
+}
+#toplogo {
+  display:block;
+  background-image: url(pics/kolab_logo.png);
+  background-color: #B0BCD0;
+  width: 245px;
+  height: 70px;
+  margin-left: 1em;
+  margin-top: 0.4em;
+  float: left;
+}
+#toptitle {
+  display:block;
+  text-align: right;
+  font-size: 200%;
+  padding-right: 1em;
+  padding-top: 0.5em;
+}
+#topuserinfo {
+  display:block;
+  background-color: #B0BCD0;
+  font-size: 80%;
+  padding: 0.1em;
+  border-bottom: solid 1px black;
+  text-align: right;
+}
+#topmenu {
+  background-color: #B0BCD0;
+  font-size: 90%;
+  border-bottom: solid 1px black;
+}
+#submenu {
+  background-color: #EEEEEE;
+  border-bottom: solid 1px black;
+  font-size: 90%;
+}
+
+.topmenuitem {
+  background-color: #B0BCD0;
+  border-right: solid 1px black;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  margin: 0px;
+}
+.topmenuitemselected {
+  background-color: #EEEEEE;
+  border-right: solid 1px black;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  margin: 0px;
+  border-bottom: solid 1px #EEEEEE;
+}
+.submenuitem {
+}
+.submenuitemselected {
+}
+.alphagroupitem {
+}
+.alphagroupitemselected {
+  font-weight:bold
+}
+#logout {
+  color: red;
+}
+#maintitle {
+  font-size: 200%;
+}
+#maincontent {
+  display:block;
+  padding: 1em;
+  margin: 1em;
+}
+#errorcontent {
+  display:block;
+  padding: 0.2em;
+  margin: 1em;
+  text-align: left;
+  color: red;
+  background-color: #EEEEEE;
+  border: solid 1px black;
+}
+#errorheader {
+  display:block;
+  text-align: left;
+  color: black;
+  background-color: #EEEEEE;
+  font-size: 150%;
+}
+#messagecontent {
+  display:block;
+  padding: 0.2em;
+  margin: 1em;
+  text-align: left;
+  color: green;
+  background-color: #EEEEEE;
+  border: solid 1px black;
+}
+#messageheader {
+  display:block;
+  text-align: left;
+  color: black;
+  background-color: #EEEEEE;
+  font-size: 150%;
+}
+.contenttext {
+  margin: 10px;
+}
+.contenttable {
+  width: 100%;
+  background-color: black;
+  border: 0px;
+}
+.contentroweven {
+  background-color: #C0CDE0;
+  margin: 0px;
+}
+.contentrowodd {
+  background-color: #D0DDF0;
+  margin: 0px;
+}
+.contentcell {
+  font-size: 90%;
+  padding: .1em .5em .1em .5em;
+  margin: 0px;
+/*  text-align: center; */
+}
+.actioncell {
+  font-size: 90%;
+  padding: .1em .5em .1em .5em;
+  width: 10%;
+  margin: 0px;
+  text-align: center;
+}
+.contentform {
+  /*float: left;*/
+  padding: .1em .5em .1em .5em;
+  background-color: #EEEEEE;
+  border: solid 1px black;
+}
+.contentformtable {
+  font-size: 90%;
+}
+.langcombo {
+  font-size: 80%;
+}
+
+#validators {
+  text-align: right;
+}
+
+th {
+  background-color: #EEEEEE;
+  border: 0px;
+}
+
+.ctrl {
+  background-color: #E0E3E0;
+  border: solid 1px black;
+  padding: .2em .5em .2em .5em;
+}
+
+.required_asterisk {
+  color: red;
+  font-size: 80%;
+  text-align: right;
+}
+
+label {
+  cursor: pointer;
+}
+
+.align_center {
+  text-align: center;
+}
+
+.align_right {
+  text-align: right;
+}
+
+.align_left {
+  text-align: left;
+}