doc/sample-insert-sharedfolder_types.php lib/api lib/Auth lib/Auth.php lib/client lib/kolab_api_controller.php lib/kolab_api_service.php lib/kolab_client_task.php lib/locale public_html/js public_html/skins

Jeroen van Meeuwen vanmeeuwen at kolabsys.com
Sat Apr 13 17:41:41 CEST 2013


 doc/sample-insert-sharedfolder_types.php              |   86 ++++
 lib/Auth.php                                          |   30 +
 lib/Auth/LDAP.php                                     |   69 +++
 lib/api/kolab_api_service_sharedfolder.php            |  216 +++++++++++
 lib/api/kolab_api_service_sharedfolder_types.php      |   64 +++
 lib/api/kolab_api_service_sharedfolders.php           |   77 ++++
 lib/client/kolab_client_task_main.php                 |   15 
 lib/client/kolab_client_task_sharedfolder.php         |  338 ++++++++++++++++++
 lib/kolab_api_controller.php                          |    9 
 lib/kolab_api_service.php                             |    4 
 lib/kolab_client_task.php                             |    2 
 lib/locale/en_US.php                                  |   15 
 public_html/js/kolab_admin.js                         |   54 ++
 public_html/skins/default/images/sharedfolders.png    |binary
 public_html/skins/default/style.css                   |    4 
 public_html/skins/default/templates/sharedfolder.html |   17 
 16 files changed, 987 insertions(+), 13 deletions(-)

New commits:
commit c088a04b6a5128bf0a3f23c0e4ba56e2c6041343
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Sat Apr 13 17:41:13 2013 +0200

    Add shared folder management functionality to the Web Administration Panel Client and API interfaces

diff --git a/doc/sample-insert-sharedfolder_types.php b/doc/sample-insert-sharedfolder_types.php
new file mode 100644
index 0000000..e0609fe
--- /dev/null
+++ b/doc/sample-insert-sharedfolder_types.php
@@ -0,0 +1,86 @@
+#!/usr/bin/php
+<?php
+
+    if (isset($_SERVER["REQUEST_METHOD"]) && !empty($SERVER["REQUEST_METHOD"])) {
+        die("Not intended for execution through the webserver, sorry!");
+    }
+
+    require_once("lib/functions.php");
+
+    $db   = SQL::get_instance();
+
+    $result = $db->query("TRUNCATE `sharedfolder_types`");
+
+    $attributes = Array(
+            "auto_form_fields" => Array(
+                ),
+            "fields" => Array(
+                    "kolabfoldertype" => Array(
+                            "contact",
+                        ),
+                    "objectclass" => Array(
+                            "top",
+                            "kolabsharedfolder",
+                        ),
+                ),
+            "form_fields" => Array(
+/* TODO: Pending implementation of a folder acl list form widget - see #1752
+                    "acl" => Array(
+                            "type" => "folder_acl_list",
+                            "optional" => true,
+                        ),
+*/
+                    "cn" => Array(),
+                ),
+        );
+
+    $result = $db->query("INSERT INTO `sharedfolder_types` (`key`, `name`, `description`, `attributes`) " .
+                "VALUES ('addressbook','Shared Address Book', 'A shared address book'," .
+                "'" . json_encode($attributes) . "')");
+
+    $attributes["fields"]["kolabfoldertype"] = Array('event');
+    $result = $db->query("INSERT INTO `sharedfolder_types` (`key`, `name`, `description`, `attributes`) " .
+                "VALUES ('calendar','Shared Calendar', 'A shared calendar'," .
+                "'" . json_encode($attributes) . "')");
+
+    $attributes["fields"]["kolabfoldertype"] = Array('journal');
+    $result = $db->query("INSERT INTO `sharedfolder_types` (`key`, `name`, `description`, `attributes`) " .
+                "VALUES ('journal','Shared Journal', 'A shared journal'," .
+                "'" . json_encode($attributes) . "')");
+
+    $attributes["fields"]["kolabfoldertype"] = Array('task');
+    $result = $db->query("INSERT INTO `sharedfolder_types` (`key`, `name`, `description`, `attributes`) " .
+                "VALUES ('task','Shared Tasks', 'A shared tasks folder'," .
+                "'" . json_encode($attributes) . "')");
+
+    $attributes["fields"]["kolabfoldertype"] = Array('mail');
+    $attributes["form_fields"]["alias"] = Array(
+            "type" => "list",
+            "optional" => true,
+        );
+
+    $attributes["form_fields"]["kolabdelegate"] = Array(
+            "type" => "list",
+            "autocomplete" => true,
+            "optional" => true,
+        );
+
+    $attributes["form_fields"]["kolaballowsmtprecipient"] = Array(
+            "type" => "list",
+            "optional" => true,
+        );
+
+    $attributes["form_fields"]["kolaballowsmtpsender"] = Array(
+            "type" => "list",
+            "optional" => true,
+        );
+
+    $attributes["form_fields"]["kolabtargetfolder"] = Array();
+    $attributes["form_fields"]["mail"] = Array();
+    $attributes["fields"]["objectclass"][] = "mailrecipient";
+
+    $result = $db->query("INSERT INTO `sharedfolder_types` (`key`, `name`, `description`, `attributes`) " .
+                "VALUES ('mail','Shared Mail Folder', 'A shared mail folder'," .
+                "'" . json_encode($attributes) . "')");
+
+?>
diff --git a/lib/Auth.php b/lib/Auth.php
index 1b795a5..0c698c4 100644
--- a/lib/Auth.php
+++ b/lib/Auth.php
@@ -315,6 +315,11 @@ class Auth {
         return $this->auth_instance($domain)->list_roles($attributes, $search, $params);
     }
 
+    public function list_sharedfolders($domain = NULL, $attributes = array(), $search = array(), $params = array())
+    {
+        return $this->auth_instance($domain)->list_sharedfolders($attributes, $search, $params);
+    }
+
     public function primary_for_valid_domain($domain)
     {
         $this->domains = $this->list_domains();
@@ -392,6 +397,31 @@ class Auth {
         return $this->auth_instance()->role_info($roledata);
     }
 
+    public function sharedfolder_add($attributes, $typeid = null)
+    {
+        return $this->auth_instance()->sharedfolder_add($attributes, $typeid);
+    }
+
+    public function sharedfolder_edit($sharedfolder, $attributes, $typeid = null)
+    {
+        return $this->auth_instance()->sharedfolder_edit($sharedfolder, $attributes, $typeid);
+    }
+
+    public function sharedfolder_delete($subject)
+    {
+        return $this->auth_instance()->sharedfolder_delete($subject);
+    }
+
+    public function sharedfolder_find_by_attribute($attribute)
+    {
+        return $this->auth_instance()->sharedfolder_find_by_attribute($attribute);
+    }
+
+    public function sharedfolder_info($sharedfolderdata)
+    {
+        return $this->auth_instance()->sharedfolder_info($sharedfolderdata);
+    }
+
     public function search()
     {
         return call_user_func_array(Array($this->auth_instance(), 'search'), func_get_args());
diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php
index 54fa946..74cab49 100644
--- a/lib/Auth/LDAP.php
+++ b/lib/Auth/LDAP.php
@@ -233,6 +233,9 @@ class LDAP extends Net_LDAP3 {
             case "role":
                 return parent::effective_rights($this->_subject_base_dn("role"));
                 break;
+            case "sharedfolder":
+                return parent::effective_rights($this->_subject_base_dn("sharedfolder"));
+                break;
             case "user":
                 return parent::effective_rights($this->_subject_base_dn("user"));
                 break;
@@ -399,6 +402,20 @@ class LDAP extends Net_LDAP3 {
         return $this->_list($base_dn, $filter, 'sub', $attributes, $search, $params);
     }
 
+    public function list_sharedfolders($attributes = array(), $search = array(), $params = array())
+    {
+        $this->_log(LOG_DEBUG, "Auth::LDAP::list_sharedfolders(" . var_export($attributes, true) . ", " . var_export($search, true) . ", " . var_export($params, true));
+
+        $base_dn = $this->_subject_base_dn('sharedfolder');
+        $filter  = $this->conf->get('sharedfolder_filter');
+
+        if (!$filter) {
+            $filter = "(&(objectclass=*)(!(objectclass=organizationalunit)))";
+        }
+
+        return $this->_list($base_dn, $filter, 'sub', $attributes, $search, $params);
+    }
+
     public function list_users($attributes = array(), $search = array(), $params = array())
     {
         $this->_log(LOG_DEBUG, "Auth::LDAP::list_users(" . var_export($attributes, true) . ", " . var_export($search, true) . ", " . var_export($params, true));
@@ -527,6 +544,58 @@ class LDAP extends Net_LDAP3 {
         return $this->_read($role_dn, $attributes);
     }
 
+    public function sharedfolder_add($attrs, $typeid = null)
+    {
+        $base_dn = $this->entry_base_dn('sharedfolder', $typeid);
+
+        // TODO: The rdn is configurable as well.
+        // Use [$type_str . "_"]user_rdn_attr
+        $dn = "cn=" . $attrs['cn'] . "," . $base_dn;
+
+        return $this->entry_add($dn, $attrs);
+    }
+
+    public function sharedfolder_delete($sharedfolder)
+    {
+        return $this->entry_delete($sharedfolder);
+    }
+
+    public function sharedfolder_edit($sharedfolder, $attributes, $typeid = null)
+    {
+        $sharedfolder = $this->sharedfolder_info($sharedfolder, array_keys($attributes));
+
+        if (empty($sharedfolder)) {
+            return false;
+        }
+
+        $sharedfolder_dn = key($sharedfolder);
+
+        // We should start throwing stuff over the fence here.
+        return $this->modify_entry($sharedfolder_dn, $sharedfolder[$sharedfolder_dn], $attributes);
+    }
+
+    public function sharedfolder_find_by_attribute($attribute)
+    {
+        return $this->entry_find_by_attribute($attribute);
+    }
+
+    public function sharedfolder_info($sharedfolder, $attributes = array('*'))
+    {
+        $this->_log(LOG_DEBUG, "Auth::LDAP::sharedfolder_info() for sharedfolder " . var_export($sharedfolder, true));
+        $this->bind($_SESSION['user']->user_bind_dn, $_SESSION['user']->user_bind_pw);
+
+        $sharedfolder_dn = $this->entry_dn($sharedfolder);
+
+        if (!$sharedfolder_dn) {
+            return false;
+        }
+
+        $this->read_prepare($attributes);
+
+        return $this->_read($sharedfolder_dn, $attributes);
+    }
+
+
     public function search($base_dn, $filter = '(objectclass=*)', $scope = 'sub', $sort = NULL, $search = array())
     {
         if (isset($_SESSION['user']->user_bind_dn) && !empty($_SESSION['user']->user_bind_dn)) {
diff --git a/lib/api/kolab_api_service_sharedfolder.php b/lib/api/kolab_api_service_sharedfolder.php
new file mode 100644
index 0000000..3213536
--- /dev/null
+++ b/lib/api/kolab_api_service_sharedfolder.php
@@ -0,0 +1,216 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab Web Admin Panel                           |
+ |                                                                          |
+ | Copyright (C) 2011-2012, Kolab Systems AG                                |
+ |                                                                          |
+ | This program is free software: you can redistribute it and/or modify     |
+ | it under the terms of the GNU Affero General Public License as published |
+ | by the Free Software Foundation, either version 3 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 Affero General Public License for more details.                      |
+ |                                                                          |
+ | You should have received a copy of the GNU Affero General Public License |
+ | along with this program. If not, see <http://www.gnu.org/licenses/>      |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com>                      |
+ | Author: Jeroen van Meeuwen <vanmeeuwen at kolabsys.com>                     |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * Service providing shared folder data management
+ */
+class kolab_api_service_sharedfolder extends kolab_api_service
+{
+    /**
+     * Returns service capabilities.
+     *
+     * @param string $domain Domain name
+     *
+     * @return array Capabilities list
+     */
+    public function capabilities($domain)
+    {
+        //console("kolab_api_service_group::capabilities");
+
+        $auth             = Auth::get_instance();
+        $effective_rights = $auth->list_rights('sharedfolder');
+        $rights           = array();
+
+        if (in_array('add', $effective_rights['entryLevelRights'])) {
+            $rights['add'] = "w";
+        }
+
+        if (in_array('delete', $effective_rights['entryLevelRights'])) {
+            $rights['delete'] = "w";
+        }
+
+        if (in_array('modrdn', $effective_rights['entryLevelRights'])) {
+            $rights['edit'] = "w";
+        }
+
+        if (in_array('read', $effective_rights['entryLevelRights'])) {
+            $rights['info'] = "r";
+            $rights['find'] = "r";
+        }
+
+        $rights['effective_rights'] = "r";
+
+        return $rights;
+    }
+
+    /**
+     * Create a shared folder.
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return array|bool User attributes or False on error.
+     */
+    public function sharedfolder_add($getdata, $postdata)
+    {
+        //console("sharedfolder_add()", $postdata);
+
+        $sharedfolder_attributes = $this->parse_input_attributes('sharedfolder', $postdata);
+
+        //console("sharedfolder_add()", $sharedfolder_attributes);
+
+        // TODO: The cn needs to be unique
+        $auth = Auth::get_instance();
+        $result = $auth->sharedfolder_add($sharedfolder_attributes, $postdata['type_id']);
+
+        if ($result) {
+            return $sharedfolder_attributes;
+        }
+
+        return false;
+    }
+
+    /**
+     * Detete a shared folder.
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return bool True on success, False on failure
+     */
+    public function sharedfolder_delete($getdata, $postdata)
+    {
+        //console("sharedfolder_delete()", $getdata, $postdata);
+        if (!isset($postdata['sharedfolder'])) {
+            return false;
+        }
+
+        // TODO: Input validation
+        $auth   = Auth::get_instance();
+        $result = $auth->sharedfolder_delete($postdata['sharedfolder']);
+
+        if ($result) {
+            return $result;
+        }
+
+        return false;
+    }
+
+    public function sharedfolder_edit($getdata, $postdata)
+    {
+        //console("\$postdata to sharedfolder_edit()", $postdata);
+
+        $sharedfolder_attributes = $this->parse_input_attributes('sharedfolder', $postdata);
+
+        //console("\$sharedfolder_attributes as result from parse_input_attributes", $sharedfolder_attributes);
+
+        $sharedfolder   = $postdata['id'];
+
+        $auth   = Auth::get_instance();
+        $result = $auth->sharedfolder_edit($sharedfolder, $sharedfolder_attributes, $postdata['type_id']);
+
+        // Return the $mod_array
+        if ($result) {
+            return $result;
+        }
+
+        return false;
+
+    }
+
+    public function sharedfolder_effective_rights($getdata, $postdata)
+    {
+        $auth = Auth::get_instance();
+        $effective_rights = $auth->list_rights(empty($getdata['sharedfolder']) ? 'sharedfolder' : $getdata['sharedfolder']);
+        return $effective_rights;
+    }
+
+    /**
+     * User information.
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return array|bool User attributes, False on error
+     */
+    public function sharedfolder_info($getdata, $postdata)
+    {
+        if (!isset($getdata['sharedfolder'])) {
+            return false;
+        }
+
+        $auth   = Auth::get_instance();
+        $result = $auth->sharedfolder_info($getdata['sharedfolder']);
+
+        // normalize result
+        $result = $this->parse_result_attributes('sharedfolder', $result);
+
+        //console($result);
+
+        if ($result) {
+            return $result;
+        }
+
+        return false;
+    }
+
+    /**
+     * Find a shared folder and return its data.
+     * It is a combination of sharedfolder.info and sharedfolders.list with search capabilities
+     * If the search returns only one record we'll return sharedfolder data.
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return array|bool Resource attributes, False on error
+     */
+    public function sharedfolder_find($get, $post)
+    {
+        $auth       = Auth::get_instance();
+        $attributes = array('');
+        $params     = array('page_size' => 2);
+        $search     = $this->parse_list_search($post);
+
+        // find shared folder(s)
+        $sharedfolders = $auth->list_sharedfolders(null, $attributes, $search, $params);
+
+        if (empty($sharedfolders) || empty($sharedfolders['list']) || $sharedfolders['count'] > 1) {
+            return false;
+        }
+
+        // get shared folder data
+        $result = $auth->sharedfolder_info(key($sharedfolders['list']));
+
+        // normalize result
+        $result = $this->parse_result_attributes('sharedfolder', $result);
+
+        if ($result) {
+            return $result;
+        }
+
+        return false;
+    }
+
+}
diff --git a/lib/api/kolab_api_service_sharedfolder_types.php b/lib/api/kolab_api_service_sharedfolder_types.php
new file mode 100644
index 0000000..972ca4e
--- /dev/null
+++ b/lib/api/kolab_api_service_sharedfolder_types.php
@@ -0,0 +1,64 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab Web Admin Panel                           |
+ |                                                                          |
+ | Copyright (C) 2011-2012, Kolab Systems AG                                |
+ |                                                                          |
+ | This program is free software: you can redistribute it and/or modify     |
+ | it under the terms of the GNU Affero General Public License as published |
+ | by the Free Software Foundation, either version 3 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 Affero General Public License for more details.                      |
+ |                                                                          |
+ | You should have received a copy of the GNU Affero General Public License |
+ | along with this program. If not, see <http://www.gnu.org/licenses/>      |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com>                      |
+ | Author: Jeroen van Meeuwen <vanmeeuwen at kolabsys.com>                     |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ *
+ */
+class kolab_api_service_sharedfolder_types extends kolab_api_service
+{
+    /**
+     * Returns service capabilities.
+     *
+     * @param string $domain Domain name
+     *
+     * @return array Capabilities list
+     */
+    public function capabilities($domain)
+    {
+        return array(
+            'list' => 'r',
+        );
+    }
+
+    /**
+     * Shared folder types listing.
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return array List result with 'list' and 'count' items
+     */
+    public function sharedfolder_types_list($get, $post)
+    {
+        $sharedfolder_types = $this->object_types('sharedfolder');
+
+        Log::trace("api/sharedfolder_types_list()", $sharedfolder_types);
+
+        return array(
+            'list'  => $sharedfolder_types,
+            'count' => count($sharedfolder_types),
+        );
+    }
+}
diff --git a/lib/api/kolab_api_service_sharedfolders.php b/lib/api/kolab_api_service_sharedfolders.php
new file mode 100644
index 0000000..03c7a6c
--- /dev/null
+++ b/lib/api/kolab_api_service_sharedfolders.php
@@ -0,0 +1,77 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab Web Admin Panel                           |
+ |                                                                          |
+ | Copyright (C) 2011-2012, Kolab Systems AG                                |
+ |                                                                          |
+ | This program is free software: you can redistribute it and/or modify     |
+ | it under the terms of the GNU Affero General Public License as published |
+ | by the Free Software Foundation, either version 3 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 Affero General Public License for more details.                      |
+ |                                                                          |
+ | You should have received a copy of the GNU Affero General Public License |
+ | along with this program. If not, see <http://www.gnu.org/licenses/>      |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com>                      |
+ | Author: Jeroen van Meeuwen <vanmeeuwen at kolabsys.com>                     |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * Service providing shared folders listing
+ */
+class kolab_api_service_sharedfolders extends kolab_api_service
+{
+    public $list_attribs = array(
+        'alias',
+        'cn',
+        'entrydn',
+        'mail',
+        'kolabtargetfolder',
+        'kolabfoldertype',
+        'objectclass',
+    );
+
+
+    /**
+     * Returns service capabilities.
+     *
+     * @param string $domain Domain name
+     *
+     * @return array Capabilities list
+     */
+    public function capabilities($domain)
+    {
+        return array(
+            'list' => 'r',
+        );
+    }
+
+    /**
+     * Shared folder listing (with searching).
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return array List result with 'list' and 'count' items
+     */
+    public function sharedfolders_list($get, $post)
+    {
+        $auth = Auth::get_instance();
+
+        $attributes = $this->parse_list_attributes($post);
+        $params = $this->parse_list_params($post);
+        $search = $this->parse_list_search($post);
+
+        $resources = $auth->list_sharedfolders(null, $attributes, $search, $params);
+
+        return $resources;
+    }
+
+}
diff --git a/lib/client/kolab_client_task_main.php b/lib/client/kolab_client_task_main.php
index b88fa40..e31f1f9 100644
--- a/lib/client/kolab_client_task_main.php
+++ b/lib/client/kolab_client_task_main.php
@@ -25,13 +25,14 @@
 class kolab_client_task_main extends kolab_client_task
 {
     protected $_menu = array(
-        'user'      => 'users',
-        'group'     => 'groups',
-        'domain'    => 'domains',
-        'role'      => 'roles',
-        'resource'  => 'resources',
-        'settings'  => 'settings',
-        'about'     => 'about',
+        'user'          => 'users',
+        'group'         => 'groups',
+        'domain'        => 'domains',
+        'role'          => 'roles',
+        'resource'      => 'resources',
+        'sharedfolder'  => 'sharedfolders',
+        'settings'      => 'settings',
+        'about'         => 'about',
     );
 
 
diff --git a/lib/client/kolab_client_task_sharedfolder.php b/lib/client/kolab_client_task_sharedfolder.php
new file mode 100644
index 0000000..cf55602
--- /dev/null
+++ b/lib/client/kolab_client_task_sharedfolder.php
@@ -0,0 +1,338 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab Web Admin Panel                           |
+ |                                                                          |
+ | Copyright (C) 2011-2012, Kolab Systems AG                                |
+ |                                                                          |
+ | This program is free software: you can redistribute it and/or modify     |
+ | it under the terms of the GNU Affero General Public License as published |
+ | by the Free Software Foundation, either version 3 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 Affero General Public License for more details.                      |
+ |                                                                          |
+ | You should have received a copy of the GNU Affero General Public License |
+ | along with this program. If not, see <http://www.gnu.org/licenses/>      |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com>                      |
+ +--------------------------------------------------------------------------+
+*/
+
+class kolab_client_task_sharedfolder extends kolab_client_task
+{
+    protected $ajax_only = true;
+
+    protected $menu = array(
+        'add'  => 'sharedfolder.add',
+    );
+
+    /**
+     * Default action.
+     */
+    public function action_default()
+    {
+        $this->output->set_object('content', 'sharedfolder', true);
+        $this->output->set_object('task_navigation', $this->menu());
+
+        $this->action_list();
+
+        // display form to add a shared folder if logged-in user has right to do so
+        $caps = $this->get_capability('actions');
+        if (!empty($caps['sharedfolder.add'])) {
+            $this->action_add();
+        }
+        else {
+            $this->output->command('set_watermark', 'taskcontent');
+        }
+    }
+
+    /**
+     * Users list action.
+     */
+    public function action_list()
+    {
+        $page_size = 20;
+        $page      = (int) self::get_input('page', 'POST');
+        if (!$page || $page < 1) {
+            $page = 1;
+        }
+
+        // request parameters
+        $post = array(
+            'attributes' => array('cn'),
+//            'sort_order' => 'ASC',
+            'sort_by'    => array('cn'),
+            'page_size'  => $page_size,
+            'page'       => $page,
+        );
+
+        // search parameters
+        if (!empty($_POST['search'])) {
+            $search = self::get_input('search', 'POST', true);
+            $field  = self::get_input('field',  'POST');
+            $method = self::get_input('method', 'POST');
+
+            $search_request = array(
+                $field => array(
+                    'value' => $search,
+                    'type'  => $method,
+                ),
+            );
+        }
+        else if (!empty($_POST['search_request'])) {
+            $search_request = self::get_input('search_request', 'POST');
+            $search_request = @unserialize(base64_decode($search_request));
+        }
+
+        if (!empty($search_request)) {
+            $post['search']          = $search_request;
+            $post['search_operator'] = 'OR';
+        }
+
+        // get shared folders list
+        $result = $this->api_post('sharedfolders.list', null, $post);
+        $count  = $result->get('count');
+        $result = (array) $result->get('list');
+
+        //console($result);
+
+        // calculate records
+        if ($count) {
+            $start = 1 + max(0, $page - 1) * $page_size;
+            $end   = min($start + $page_size - 1, $count);
+        }
+
+        $rows = $head = $foot = array();
+        $cols = array('name');
+        $i    = 0;
+
+        // table header
+        $head[0]['cells'][] = array('class' => 'name', 'body' => $this->translate('sharedfolder.list'));
+
+        // table footer (navigation)
+        if ($count) {
+            $pages = ceil($count / $page_size);
+            $prev  = max(0, $page - 1);
+            $next  = $page < $pages ? $page + 1 : 0;
+
+            $count_str = kolab_html::span(array(
+                'content' => $this->translate('list.records', $start, $end, $count)), true);
+            $prev = kolab_html::a(array(
+                'class' => 'prev' . ($prev ? '' : ' disabled'),
+                'href'  => '#',
+                'onclick' => $prev ? "kadm.command('sharedfolder.list', {page: $prev})" : "return false",
+            ));
+            $next = kolab_html::a(array(
+                'class' => 'next' . ($next ? '' : ' disabled'),
+                'href'  => '#',
+                'onclick' => $next ? "kadm.command('sharedfolder.list', {page: $next})" : "return false",
+            ));
+
+            $foot_body = kolab_html::span(array('content' => $prev . $count_str . $next));
+        }
+        $foot[0]['cells'][] = array('class' => 'listnav', 'body' => $foot_body);
+
+        // table body
+        if (!empty($result)) {
+            foreach ($result as $idx => $item) {
+                if (!is_array($item) || empty($item['cn'])) {
+                    continue;
+                }
+
+                $i++;
+                $cells = array();
+                $cells[] = array('class' => 'name', 'body' => kolab_html::escape($item['cn']),
+                    'onclick' => "kadm.command('sharedfolder.info', '$idx')");
+                $rows[] = array('id' => $i, 'class' => 'selectable', 'cells' => $cells);
+            }
+        }
+        else {
+            $rows[] = array('cells' => array(
+                0 => array('class' => 'empty-body', 'body' => $this->translate('sharedfolder.norecords')
+            )));
+        }
+
+        $table = kolab_html::table(array(
+            'id'    => 'sharedfolderlist',
+            'class' => 'list',
+            'head'  => $head,
+            'body'  => $rows,
+            'foot'  => $foot,
+        ));
+
+        if ($this->action == 'list') {
+            $this->output->command('set_watermark', 'taskcontent');
+        }
+
+        $this->output->set_env('search_request', $search_request ? base64_encode(serialize($search_request)) : null);
+        $this->output->set_env('list_page', $page);
+        $this->output->set_env('list_count', $count);
+        $this->output->set_env('list_size', count($result));
+        $this->output->set_object('sharedfolderlist', $table);
+    }
+
+    /**
+     * Resource adding (form) action.
+     */
+    public function action_add()
+    {
+        $data   = $this->get_input('data', 'POST');
+        $output = $this->sharedfolder_form(null, $data, true);
+
+        $this->output->set_object('taskcontent', $output);
+    }
+
+    /**
+     * Resource information (form) action.
+     */
+    public function action_info()
+    {
+        $id             = $this->get_input('id', 'POST');
+        $result         = $this->api_get('sharedfolder.info', array('sharedfolder' => $id));
+        $sharedfolder   = $result->get();
+
+        //console("action_info()", $sharedfolder);
+
+        $output     = $this->sharedfolder_form(null, $sharedfolder);
+
+        $this->output->set_object('taskcontent', $output);
+    }
+
+    private function sharedfolder_form($attribs, $data = array())
+    {
+        if (empty($attribs['id'])) {
+            $attribs['id'] = 'sharedfolder-form';
+        }
+
+        //console("sharedfolder_form(\$attribs, \$data)", $attribs, $data);
+
+        // Form sections
+        $sections = array(
+            'system'        => 'sharedfolder.system',
+            'other'         => 'sharedfolder.other',
+        );
+
+        // field-to-section map and fields order
+        $fields_map = array(
+            'type_id'                   => 'system',
+            'type_id_name'              => 'system',
+
+            'cn'                        => 'system',
+            'ou'                        => 'system',
+            'preferredlanguage'         => 'system',
+
+            'mail'                      => 'system',
+            'alias'                     => 'system',
+            'mailalternateaddress'      => 'system',
+
+            'member'                    => 'system',
+            'uniquemember'              => 'system',
+            'memberurl'                 => 'system',
+
+            'nsrole'                    => 'system',
+            'nsroledn'                  => 'system',
+
+            /* Kolab Settings */
+            'kolabhomeserver'           => 'system',
+            'mailhost'                  => 'system',
+            'mailquota'                 => 'system',
+            'kolabfreebusyfuture'       => 'system',
+            'kolabinvitationpolicy'     => 'system',
+            'kolabdelegate'             => 'system',
+            'kolaballowsmtprecipient'   => 'system',
+            'kolaballowsmtpsender'      => 'system',
+        );
+
+        // Prepare fields
+        list($fields, $types, $type) = $this->form_prepare('sharedfolder', $data);
+
+        //console("Result from form_prepare", $fields, $types, $type);
+
+        $add_mode  = empty($data['id']);
+        $accttypes = array();
+
+        foreach ($types as $idx => $elem) {
+            $accttypes[$idx] = array('value' => $idx, 'content' => $elem['name']);
+        }
+
+        // Add sharedfolder type id selector
+        $fields['type_id'] = array(
+            'section'  => 'system',
+            'type'     => kolab_form::INPUT_SELECT,
+            'options'  => $accttypes,
+            'onchange' => "kadm.sharedfolder_save(true, 'system')",
+        );
+
+        //console($accttypes);
+
+        // Hide account type selector if there's only one type
+        if (count($accttypes) < 2 || !$add_mode) {
+            //console("setting type_id form type to hidden");
+            $fields['type_id']['type'] = kolab_form::INPUT_HIDDEN;
+        }
+
+        // Create mode
+        if ($add_mode) {
+            // Page title
+            $title = $this->translate('sharedfolder.add');
+        }
+        // Edit mode
+        else {
+            $title = $data['cn'];
+
+            // Add sharedfolder type name
+            $fields['type_id_name'] = array(
+                'label'    => 'sharedfolder.type_id',
+                'section'  => 'system',
+                'value'    => $accttypes[$type]['content'],
+            );
+        }
+
+        // Create form object and populate with fields
+        $form = $this->form_create('sharedfolder', $attribs, $sections, $fields, $fields_map, $data, $add_mode);
+
+        $form->set_title(kolab_html::escape($title));
+
+        return $form->output();
+    }
+
+    /**
+     * Users search form.
+     *
+     * @return string HTML output of the form
+     */
+    public function search_form()
+    {
+        $form = new kolab_form(array('id' => 'search-form'));
+
+        $form->add_section('criteria', kolab_html::escape($this->translate('search.criteria')));
+        $form->add_element(array(
+            'section' => 'criteria',
+            'label'   => $this->translate('search.field'),
+            'name'    => 'field',
+            'type'    => kolab_form::INPUT_SELECT,
+            'options' => array(
+                'cn'    => kolab_html::escape($this->translate('search.name')),
+                'email' => kolab_html::escape($this->translate('search.email')),
+                'uid'   => kolab_html::escape($this->translate('search.uid')),
+            ),
+        ));
+        $form->add_element(array(
+            'section' => 'criteria',
+            'label'   => $this->translate('search.method'),
+            'name'    => 'method',
+            'type'    => kolab_form::INPUT_SELECT,
+            'options' => array(
+                'both'   => kolab_html::escape($this->translate('search.contains')),
+                'exact'  => kolab_html::escape($this->translate('search.is')),
+                'prefix' => kolab_html::escape($this->translate('search.prefix')),
+            ),
+        ));
+
+        return $form->output();
+    }
+}
diff --git a/lib/kolab_api_controller.php b/lib/kolab_api_controller.php
index a4a4b78..bd62778 100644
--- a/lib/kolab_api_controller.php
+++ b/lib/kolab_api_controller.php
@@ -62,18 +62,21 @@ class kolab_api_controller
         $this->add_service('domain_types',      'kolab_api_service_domain_types');
         $this->add_service('domains',           'kolab_api_service_domains');
         $this->add_service('form_value',        'kolab_api_service_form_value');
-        $this->add_service('group_types',       'kolab_api_service_group_types');
         $this->add_service('group',             'kolab_api_service_group');
+        $this->add_service('group_types',       'kolab_api_service_group_types');
         $this->add_service('groups',            'kolab_api_service_groups');
-        $this->add_service('resource_types',    'kolab_api_service_resource_types');
         $this->add_service('resource',          'kolab_api_service_resource');
+        $this->add_service('resource_types',    'kolab_api_service_resource_types');
         $this->add_service('resources',         'kolab_api_service_resources');
+        $this->add_service('sharedfolder',      'kolab_api_service_sharedfolder');
+        $this->add_service('sharedfolder_types','kolab_api_service_sharedfolder_types');
+        $this->add_service('sharedfolders',     'kolab_api_service_sharedfolders');
         $this->add_service('roles',             'kolab_api_service_roles');
         $this->add_service('role',              'kolab_api_service_role');
         $this->add_service('role_types',        'kolab_api_service_role_types');
         $this->add_service('type',              'kolab_api_service_type');
-        $this->add_service('user_types',        'kolab_api_service_user_types');
         $this->add_service('user',              'kolab_api_service_user');
+        $this->add_service('user_types',        'kolab_api_service_user_types');
         $this->add_service('users',             'kolab_api_service_users');
     }
 
diff --git a/lib/kolab_api_service.php b/lib/kolab_api_service.php
index 206a2b9..ca93c8a 100644
--- a/lib/kolab_api_service.php
+++ b/lib/kolab_api_service.php
@@ -32,8 +32,8 @@ abstract class kolab_api_service
     protected $conf;
     protected $controller;
     protected $db;
-    protected $supported_types_db = array('group', 'resource', 'role', 'user');
-    protected $supported_types    = array('domain', 'group', 'resource', 'role', 'user');
+    protected $supported_types_db = array('group', 'resource', 'role', 'sharedfolder', 'user');
+    protected $supported_types    = array('domain', 'group', 'resource', 'role', 'sharedfolder', 'user');
 
     /**
      * Class constructor.
diff --git a/lib/kolab_client_task.php b/lib/kolab_client_task.php
index 893f35e..e6df470 100644
--- a/lib/kolab_client_task.php
+++ b/lib/kolab_client_task.php
@@ -46,7 +46,7 @@ class kolab_client_task
     protected $menu = array();
     protected $cache = array();
     protected $devel_mode = false;
-    protected $object_types = array('user', 'group', 'role', 'resource', 'domain');
+    protected $object_types = array('user', 'group', 'role', 'resource', 'sharedfolder', 'domain');
 
     protected static $translation = array();
 
diff --git a/lib/locale/en_US.php b/lib/locale/en_US.php
index a19869c..640bddb 100644
--- a/lib/locale/en_US.php
+++ b/lib/locale/en_US.php
@@ -105,6 +105,7 @@ $LANG['menu.groups'] = 'Groups';
 $LANG['menu.resources'] = 'Resources';
 $LANG['menu.roles'] = 'Roles';
 $LANG['menu.settings'] = 'Settings';
+$LANG['menu.sharedfolders'] = 'Shared Folders';
 $LANG['menu.users'] = 'Users';
 
 $LANG['modifiersname'] = 'Modified by';
@@ -161,6 +162,19 @@ $LANG['servererror'] = 'Server Error!';
 
 $LANG['session.expired'] = 'Session has expired. Login again, please';
 
+$LANG['sharedfolder.add'] = 'Add Shared Folder';
+$LANG['sharedfolder.alias'] = 'Secondary Email Address(es)';
+$LANG['sharedfolder.cn'] = 'Folder Name';
+$LANG['sharedfolder.edit'] = 'Edit Shared Folder';
+$LANG['sharedfolder.kolaballowsmtprecipient'] = 'Recipient(s) Access List';
+$LANG['sharedfolder.kolaballowsmtpsender'] = 'Sender Access List';
+$LANG['sharedfolder.kolabdelegate'] = 'Delegate(s)';
+$LANG['sharedfolder.kolabtargetfolder'] = 'Target IMAP Folder';
+$LANG['sharedfolder.mail'] = 'Email Address';
+$LANG['sharedfolder.other'] = 'Other';
+$LANG['sharedfolder.system'] = 'System';
+$LANG['sharedfolder.type_id'] = 'Shared Folder Type';
+
 $LANG['signup.headline'] = 'Sign Up for Hosted Kolab';
 $LANG['signup.intro1'] = 'Having an account on a Kolab server is way better than just simple Email. It also provides you with full groupware functionality including synchronization for shared addressbooks, calendars, tasks, journal and more.';
 $LANG['signup.intro2'] = 'You can sign up here now for an account.';
@@ -194,6 +208,7 @@ $LANG['type.object_type'] = 'Object type';
 $LANG['type.properties'] = 'Properties';
 $LANG['type.resource'] = 'Resource';
 $LANG['type.role'] = 'Role';
+$LANG['type.sharedfolder'] = 'Shared Folder';
 $LANG['type.used_for'] = 'Hosted';
 $LANG['type.user'] = 'User';
 
diff --git a/public_html/js/kolab_admin.js b/public_html/js/kolab_admin.js
index ab2261e..c962be3 100644
--- a/public_html/js/kolab_admin.js
+++ b/public_html/js/kolab_admin.js
@@ -1636,6 +1636,60 @@ function kolab_admin()
     this.response_handler(response, 'role.edit', 'role.list');
   };
 
+  this.sharedfolder_info = function(id)
+  {
+    this.http_post('sharedfolder.info', {id: id});
+  };
+
+  this.sharedfolder_list = function(props)
+  {
+    this.list_handler('sharedfolder', props);
+  };
+
+  this.sharedfolder_delete = function(sharedfolderid)
+  {
+    this.set_busy(true, 'deleting');
+    this.api_post('sharedfolder.delete', {sharedfolder: sharedfolderid}, 'sharedfolder_delete_response');
+  };
+
+  this.sharedfolder_save = function(reload, section)
+  {
+    var data = this.serialize_form('#'+this.env.form_id),
+      action = data.id ? 'edit' : 'add';
+
+    if (reload) {
+      data.section = section;
+      this.http_post('sharedfolder.' + action, {data: data});
+      return;
+    }
+
+    this.form_error_clear();
+
+    if (!this.check_required_fields(data)) {
+      this.display_message('form.required.empty', 'error');
+      return;
+    }
+
+    this.set_busy(true, 'saving');
+    this.api_post('sharedfolder.' + action, data, 'sharedfolder_' + action + '_response');
+  };
+
+  this.sharedfolder_delete_response = function(response)
+  {
+    this.response_handler(response, 'sharedfolder.delete', 'sharedfolder.list');
+  };
+
+  this.sharedfolder_add_response = function(response)
+  {
+    this.response_handler(response, 'sharedfolder.add', 'sharedfolder.list');
+  };
+
+  this.sharedfolder_edit_response = function(response)
+  {
+    this.response_handler(response, 'sharedfolder.edit', 'sharedfolder.list');
+  };
+
+
   this.settings_type_info = function(id)
   {
     this.http_post('settings.type_info', {id: id});
diff --git a/public_html/skins/default/images/sharedfolders.png b/public_html/skins/default/images/sharedfolders.png
new file mode 100644
index 0000000..4395216
Binary files /dev/null and b/public_html/skins/default/images/sharedfolders.png differ
diff --git a/public_html/skins/default/style.css b/public_html/skins/default/style.css
index 6b30d90..fa808c6 100644
--- a/public_html/skins/default/style.css
+++ b/public_html/skins/default/style.css
@@ -981,6 +981,10 @@ fieldset.tabbed
   background: url(images/resources.png) center center no-repeat;
 }
 
+#main div.sharedfolder span.image {
+  background: url(images/sharedfolders.png) center center no-repeat;
+}
+
 #main div.settings span.image {
   background: url(images/settings.png) center center no-repeat;
 }
diff --git a/public_html/skins/default/templates/sharedfolder.html b/public_html/skins/default/templates/sharedfolder.html
new file mode 100644
index 0000000..77d09fb
--- /dev/null
+++ b/public_html/skins/default/templates/sharedfolder.html
@@ -0,0 +1,17 @@
+<div id="toc" class="sharedfolder">
+    <div id="search">
+        <div class="searchinput">
+            <input type="text" id="searchinput" name="search" value="{$engine->translate('search')}" />
+            <script type="text/javascript">search_init('sharedfolder.list')</script>
+            <span class="searchactions">
+                <span id="search-details" title="{$engine->translate('search.criteria')}" onclick="search_details()"></span>
+                <span id="search-reset" title="{$engine->translate('search.reset')}" onclick="search_reset()"></span>
+            </span>
+        </div>
+        <div class="searchdetails">{$engine->search_form()}</div>
+    </div>
+    <div id="sharedfolderlist"></div>
+</div>
+<div class="vsplitter"> </div>
+<div id="taskcontent" class="sharedfolder"></div>
+<div class="clear"></div>






More information about the commits mailing list