Projects
Kolab:Winterfell
chwala
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 27
View file
chwala.spec
Changed
@@ -37,7 +37,7 @@ %global _ap_sysconfdir %{_sysconfdir}/%{httpd_name} Name: chwala -Version: 0.5.3 +Version: 0.5.4 Release: 1%{?dist} Summary: Glorified WebDAV, done right
View file
chwala-0.5.3.tar.gz/config/config.inc.php.dist -> chwala-0.5.4.tar.gz/config/config.inc.php.dist
Changed
@@ -52,6 +52,11 @@ ); */ +// Disables listing folders from the backend storage. +// This is useful when you configured an external source(s) and +// you want to use it exclusively, ignoring Kolab folders. +$config['fileapi_backend_storage_disabled'] = false; + // Manticore service URL. Enables use of WebODF collaborative editor. // Note: this URL should be accessible from Chwala host and Roundcube host as well. $config['fileapi_manticore'] = null; @@ -76,6 +81,26 @@ // possible units: s, m, h, d, w $config['fileapi_cache_ttl'] = '1d'; +// LDAP addressbook that would be searched for user names autocomplete. +// That should be an array refering to the Roundcube's $config['ldap_public'] +// array key or complete addressbook configuration array. +$config['fileapi_users_source'] = 'kolab_addressbook'; + +// The LDAP attribute which will be used as ACL user identifier +$config['fileapi_users_field'] = 'mail'; + +// The LDAP search filter will be combined with search queries +$config['fileapi_users_filter'] = ''; + +// Include groups in searching +$config['fileapi_groups'] = false; + +// Prefix added to the group name to build IMAP ACL identifier +$config['fileapi_group_prefix'] = 'group:'; + +// The LDAP attribute (or field name) which will be used as ACL group identifier +$config['fileapi_group_field'] = 'name'; + // ------------------------------------------------ // SeaFile driver settings // ------------------------------------------------
View file
chwala-0.5.4.tar.gz/lib/api/autocomplete.php
Added
@@ -0,0 +1,57 @@ +<?php +/* + +--------------------------------------------------------------------------+ + | This file is part of the Kolab File API | + | | + | Copyright (C) 2012-2018, 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@kolabsys.com> | + +--------------------------------------------------------------------------+ +*/ + +class file_api_autocomplete extends file_api_common +{ + /** + * Request handler + */ + public function handle() + { + parent::handle(); + + if (!isset($this->args['search']) || $this->args['search'] === '') { + throw new Exception("Missing search keyword", file_api_core::ERROR_CODE); + } + + if (isset($this->args['folder']) && $this->args['folder'] !== '') { + list($driver, $path) = $this->api->get_driver($this->args['folder']); + } + else { + $driver = $this->api->get_backend(); + } + + if (!empty($this->args['mode'])) { + $mode = 0; + $mode += stripos($this->args['mode'], 'user') !== false ? file_storage::SEARCH_USER : 0; + $mode += stripos($this->args['mode'], 'group') !== false ? file_storage::SEARCH_GROUP : 0; + } + + if (empty($mode)) { + $mode = file_storage::SEARCH_USER; + } + + return $driver->autocomplete($this->args['search'], $mode); + } +}
View file
chwala-0.5.3.tar.gz/lib/api/folder_list.php -> chwala-0.5.4.tar.gz/lib/api/folder_list.php
Changed
@@ -57,7 +57,7 @@ return $folders; } - $drivers = $this->api->get_drivers(true); + $drivers = $this->api->get_drivers(true, $admin_drivers); $has_more = false; $errors = array(); @@ -114,8 +114,13 @@ } catch (Exception $e) { if ($e->getCode() == file_storage::ERROR_NOAUTH) { - // inform UI about to ask user for credentials - $errors[$title] = $this->parse_metadata($driver->driver_metadata()); + if (!in_array($title, $admin_drivers)) { + // inform UI about to ask user for credentials + $errors[$title] = $this->parse_metadata($driver->driver_metadata()); + } + else { + $errors[$title] = array('error' => file_storage::ERROR_NOAUTH); + } } } }
View file
chwala-0.5.4.tar.gz/lib/api/sharing.php
Added
@@ -0,0 +1,84 @@ +<?php +/* + +--------------------------------------------------------------------------+ + | This file is part of the Kolab File API | + | | + | Copyright (C) 2012-2018, 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@kolabsys.com> | + +--------------------------------------------------------------------------+ +*/ + +class file_api_sharing extends file_api_common +{ + /** + * Request handler + */ + public function handle() + { + parent::handle(); + + if (!isset($this->args['folder']) || $this->args['folder'] === '') { + throw new Exception("Missing folder name", file_api_core::ERROR_CODE); + } + + list($driver, $path) = $this->api->get_driver($this->args['folder']); + + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + // Required arguments: + // - action: 'submit', 'update', 'delete' + // - mode: depends on the storage driver + return $driver->sharing($path, file_storage::SHARING_MODE_UPDATE, $this->args); + } + + $form = $driver->sharing($path, file_storage::SHARING_MODE_FORM); + + if (empty($form)) { + throw new Exception("Sharing not supported", file_api_core::ERROR_UNSUPPORTED); + } + + $rights = $driver->sharing($path, file_storage::SHARING_MODE_RIGHTS); + + $this->localize_form_data($form); + + $result = array( + 'form' => $form, + 'rights' => (array) $rights, + ); + + return $result; + } + + /** + * Recurrent function to localize form data entries + */ + protected function localize_form_data(&$data, $key = null, $self = null) + { + if (!$self) { + $self = $this; + } + + if (in_array($key, array('title', 'placeholder', 'label', 'list_column_label'))) { + $data = $self->api->translate($data); + } + else if ($key == 'options') { + $data = array_map(array($self->api, 'translate'), $data); + } + else if (is_array($data)) { + array_walk($data, array($self, 'localize_form_data'), $self); + } + } +}
View file
chwala-0.5.4.tar.gz/lib/drivers/kolab/kolab_file_autocomplete.php
Added
@@ -0,0 +1,171 @@ +<?php +/* + +--------------------------------------------------------------------------+ + | This file is part of the Kolab File API | + | | + | Copyright (C) 2012-2018, 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@kolabsys.com> | + +--------------------------------------------------------------------------+ +*/ + +class kolab_file_autocomplete +{ + private $rc; + private $ldap; + + /** + * Class constructor + */ + public function __construct() + { + $this->rc = rcube::get_instance(); + } + + /** + * Search users/groups + */ + public function search($search, $with_groups = false) + { + if (!$this->init_ldap()) { + return false; + } + + $max = (int) $this->rc->config->get('autocomplete_max', 15); + $mode = (int) $this->rc->config->get('addressbook_search_mode'); + $me = $this->rc->get_user_name(); + + $this->ldap->set_pagesize($max); + + $result = $this->ldap->search('*', $search, $mode); + $users = array(); + $index = array(); + + foreach ($result->records as $record) { + $user = $record['uid']; + + if (is_array($user)) { + $user = array_filter($user); + $user = $user[0]; + } + + if (in_array($me, rcube_addressbook::get_col_values('email', $record, true))) { + continue; + } + + if ($user) { + $display = rcube_addressbook::compose_search_name($record); + $user = array('name' => $user, 'display' => $display); + $users[] = $user; + $index[] = $display ?: $user['name']; + } + } + + $group_support = $this->rc->config->get('fileapi_groups'); + $group_prefix = $this->rc->config->get('fileapi_group_prefix'); + $group_field = $this->rc->config->get('fileapi_group_field', 'name'); + + if ($with_groups && $group_support && $group_field) { + $result = $this->ldap->list_groups($search, $mode); + + foreach ($result as $record) { + $group = $record['name']; + $group_id = is_array($record[$group_field]) ? $record[$group_field][0] : $record[$group_field]; + + if ($group) { + $users[] = array('name' => ($group_prefix ? $group_prefix : '') . $group_id, 'display' => $group, 'type' => 'group'); + $index[] = $group; + } + } + } + + if (count($users)) { + array_multisort($index, SORT_ASC, SORT_LOCALE_STRING, $users); + } + + if (count($users) > $max) { + $users = array_slice($users, 0, $max); + } + + return $users; + } + + /** + * Initializes autocomplete LDAP backend + */ + private function init_ldap() + { + if ($this->ldap) { + return $this->ldap->ready; + } + + // get LDAP config + $config = $this->rc->config->get('fileapi_users_source'); + + if (empty($config)) { + return false; + } + + // not an array, use configured ldap_public source + if (!is_array($config)) { + $ldap_config = (array) $this->rc->config->get('ldap_public'); + $config = $ldap_config[$config]; + } + + $uid_field = $this->rc->config->get('fileapi_users_field', 'mail'); + $filter = $this->rc->config->get('fileapi_users_filter'); + $debug = $this->rc->config->get('ldap_debug'); + $domain = $this->rc->config->mail_domain($_SESSION['imap_host']); + + if (empty($uid_field) || empty($config)) { + return false; + } + + // get name attribute + if (!empty($config['fieldmap'])) { + $name_field = $config['fieldmap']['name']; + } + // ... no fieldmap, use the old method + if (empty($name_field)) { + $name_field = $config['name_field']; + } + + // add UID field to fieldmap, so it will be returned in a record with name + $config['fieldmap']['name'] = $name_field; + $config['fieldmap']['uid'] = $uid_field; + + // search in UID and name fields + // $name_field can be in a form of <field>:<modifier> (#1490591) + $name_field = preg_replace('/:.*$/', '', $name_field); + $search = array_unique(array($name_field, $uid_field)); + + $config['search_fields'] = $search; + $config['required_fields'] = array($uid_field); + + // set search filter + if ($filter) { + $config['filter'] = $filter; + } + + // disable vlv + $config['vlv'] = false; + + // Initialize LDAP connection + $this->ldap = new rcube_ldap($config, $debug, $domain); + + return $this->ldap->ready; + } +}
View file
chwala-0.5.3.tar.gz/lib/drivers/kolab/kolab_file_storage.php -> chwala-0.5.4.tar.gz/lib/drivers/kolab/kolab_file_storage.php
Changed
@@ -321,6 +321,7 @@ file_storage::CAPS_QUOTA => $quota, file_storage::CAPS_LOCKS => true, file_storage::CAPS_SUBSCRIPTIONS => true, + file_storage::CAPS_ACL => true, ); } @@ -1202,6 +1203,258 @@ } /** + * Sharing interface + * + * @param string $folder_name Name of a folder with full path + * @param int $mode Sharing action mode + * @param array $args POST/GET parameters + * + * @return mixed Sharing response + * @throws Exception + */ + public function sharing($folder, $mode, $args = array()) + { + $folder_name = rcube_charset::convert($folder, RCUBE_CHARSET, 'UTF7-IMAP'); + $storage = $this->rc->get_storage(); + $folder_info = $storage->folder_info($folder_name); + + if (!is_array($folder_info['rights'])) { + throw new Exception("Storage error. Failed to get folder permissions.", file_storage::ERROR); + } + + if (!in_array('a', $folder_info['rights'])) { + throw new Exception("No permissions to administer this folder.", file_storage::ERROR_FORBIDDEN); + } + + if ($mode == file_storage::SHARING_MODE_FORM) { + $form = array( + 'shares' => array( + 'title' => 'share.permissions', + 'form' => array( + 'user' => array( + 'title' => 'share.usergroup', + 'type' => 'input', + 'autocomplete' => 'user,group', + ), + 'right' => array( + 'title' => 'share.permission', + 'type' => 'select', + 'options' => array( + 'r' => 'share.readonly', + 'rw' => 'share.readwrite', + 'a' => 'share.admin', + ), + ), + ), + 'extra_fields' => array( + 'type' => 'user', + 'id' => '', + ), + ), + ); + + return $form; + } + + if ($mode == file_storage::SHARING_MODE_RIGHTS) { + $result = array(); + $acl_list = $storage->get_acl($folder_name); + + foreach ((array) $acl_list as $name => $acl) { + if ($name == $_SESSION['username']) { + continue; + } + + if (in_array('a', $acl)) { + $right = 'a'; + } + else if (in_array('i', $acl)) { + $right = 'rw'; + } + else if (in_array('r', $acl)) { + $right = 'r'; + } + else { + continue; + } + + $type = strpos($name, 'group:') === 0 ? 'group' : 'user'; + $id = $name; + + if ($type == 'group') { + $name = substr($name, 6); + } + + $result[] = array( + 'mode' => 'shares', + 'type' => $type, + 'right' => $right, + 'user' => $name, + 'id' => $id, + ); + } + + return $result; + } + + if ($mode == file_storage::SHARING_MODE_UPDATE) { + if ($args['mode'] == 'shares') { + $user = $args['id']; + if (!$user) { + $user = ($args['type'] == 'group' ? 'group:' : '') . preg_replace('/^group:/', '', $args['user']); + } + + switch ($args['right']) { + case 'r': $acl = 'lrs'; break; + case 'rw': $acl = 'lrswite'; break; + case 'a': $acl = 'lrswiteax'; break; + } + + if (empty($user) || (empty($acl) && $args['action'] != 'delete')) { + throw new Exception("Invalid input.", file_storage::ERROR); + } + + switch ($args['action']) { + case 'submit': + case 'update': + $result = $storage->set_acl($folder_name, $user, $acl); + break; + + case 'delete': + $result = $storage->delete_acl($folder_name, $user); + break; + } + } + else { + throw new Exception("Invalid input.", file_storage::ERROR); + } + + if (empty($result)) { + throw new Exception("Storage error. Failed to update share.", file_storage::ERROR); + } + + return true; + } + } + + /** + * User/group search (autocompletion) + * + * @param string $search Search string + * @param int $mode Search mode + * + * @return array Users/Groups list + * @throws Exception + */ + public function autocomplete($search, $mode) + { + $ac = new kolab_file_autocomplete($this); + + $result = $ac->search($search, $mode & file_storage::SEARCH_GROUP); + + if ($result === false) { + throw new Exception("Failed to search users", file_storage::ERROR); + } + + return $result; + } + + /** + * Convert file/folder path into a global URI. + * + * @param string $path File/folder path + * + * @return string URI + * @throws Exception + */ + public function path2uri($path) + { + $storage = $this->rc->get_storage(); + $namespace = $storage->get_namespace(); + $separator = $storage->get_hierarchy_delimiter(); + $_path = str_replace(file_storage::SEPARATOR, $separator, $path); + $owner = $this->rc->get_user_name(); + + // find the owner and remove namespace prefix + foreach (array_filter($namespace) as $type => $ns) { + foreach ($ns as $root) { + if (is_array($root) && $root[0] && strpos($_path, $root[0]) === 0) { + $path = substr($path, strlen($root[0])); + + switch ($type) { + case 'shared': + // in theory there can be more than one shared root + // we add it to dummy user name, so we can revert conversion + $owner = "shared({$root[0]})"; + break; + + case 'other': + list($user, $path) = explode(file_storage::SEPARATOR, $path, 2); +
View file
chwala-0.5.3.tar.gz/lib/drivers/seafile/seafile_api.php -> chwala-0.5.4.tar.gz/lib/drivers/seafile/seafile_api.php
Changed
@@ -142,15 +142,16 @@ /** * Send HTTP request * - * @param string $method Request method ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT') - * @param string $url Request API URL - * @param array $get GET parameters - * @param array $post POST parameters - * @param array $upload Uploaded files data + * @param string $method Request method ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT') + * @param string $url Request API URL + * @param array $get GET parameters + * @param array $post POST parameters + * @param array $upload Uploaded files data + * @param string $version API version (to replace "api2" with "api/v$version" in the URL * * @return string|array Server response */ - protected function request($method, $url, $get = null, $post = null, $upload = null) + protected function request($method, $url, $get = null, $post = null, $upload = null, $version = null) { if (!preg_match('/^https?:\/\//', $url)) { $url = $this->url . $url; @@ -161,6 +162,10 @@ $url = $this->mod_url($url); } + if ($version && $version != 2) { + $url = str_replace('/api2/', "/api/v$version/", $url); + } + if (!$this->request) { $this->config['store_body'] = true; // some methods respond with 301 redirect, we'll not follow them @@ -881,6 +886,459 @@ } /** + * Share a directory (or library) + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * @param string $right Permission ('r' or 'rw' or 'admin') + * @param string $mode Mode ('user' or 'group') + * @param string $who Username or Group ID + * @param bool $update Update an existing entry + * + * @return bool True on success, False on failure + */ + public function shared_item_add($repo_id, $dir, $right, $mode, $who, $update = false) + { + // sanity checks + if (!is_string($dir)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($repo_id === '' || !is_string($repo_id)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($mode != 'user' && $mode != 'group') { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($right != 'r' && $right != 'rw' && $right != 'admin') { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($dir === '') { + $dir = '/'; + } + + $post = array( + 'permission' => $right, + 'share_type' => $mode, + ); + + $post[$mode == 'group' ? 'group_id' : 'username'] = $who; + + $this->request($update ? 'POST' : 'PUT', "repos/$repo_id/dir/shared_items", array('p' => $dir), $post); + + return $this->is_error() === false; + } + + /** + * Update shared item permissions + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * @param string $right Permission ('r' or 'rw' or 'admin') + * @param string $mode Mode ('user' or 'group') + * @param string $who Username or Group ID + * + * @return bool True on success, False on failure + */ + public function shared_item_update($repo_id, $dir, $right, $mode, $who) + { + return $this->shared_item_add($repo_id, $dir, $right, $mode, $who, true); + } + + /** + * Un-Share a directory (or library) + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * @param string $mode Mode ('user' or 'group') + * @param string $who Username or Group ID + * + * @return bool True on success, False on failure + */ + public function shared_item_delete($repo_id, $dir, $mode, $who) + { + // sanity checks + if (!is_string($dir)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($repo_id === '' || !is_string($repo_id)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($mode != 'user' && $mode != 'group') { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($dir === '') { + $dir = '/'; + } + + $get = array( + 'share_type' => $mode, + 'p' => $dir + ); + + $get[$mode == 'group' ? 'group_id' : 'username'] = $who; + + $this->request('DELETE', "repos/$repo_id/dir/shared_items", $get); + + return $this->is_error() === false; + } + + /** + * List directory permissions (shares) + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * + * @return bool|array List of user/group info on success, False on failure + */ + public function shared_item_list($repo_id, $dir) + { + // sanity checks + if (!is_string($dir)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($repo_id === '' || !is_string($repo_id)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($dir === '') { + $dir = '/'; + } + + // Example result: + // [ + // { + // "group_info": { "id": 17, "name": "Group Name" }, + // "is_admin": false, + // "share_type": "group", + // "permission": "rw" + // }, + // { + // "user_info": { "nickname": "user", "name": "user@domain.com" }, + // "share_type": "user", + // "permission": "r" + // } + // ] + + return $this->request('GET', "repos/$repo_id/dir/shared_items", array('p' => $dir)); + } + + /** + * List share (download) links + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * + * @return bool|array List of shared links on success, False on failure + */ + public function share_link_list($repo_id, $dir)
View file
chwala-0.5.3.tar.gz/lib/drivers/seafile/seafile_file_storage.php -> chwala-0.5.4.tar.gz/lib/drivers/seafile/seafile_file_storage.php
Changed
@@ -205,6 +205,7 @@ file_storage::CAPS_MAX_UPLOAD => $max_filesize, file_storage::CAPS_QUOTA => true, file_storage::CAPS_LOCKS => true, + file_storage::CAPS_ACL => true, ); } @@ -1106,6 +1107,312 @@ } /** + * Sharing interface + * + * @param string $folder_name Name of a folder with full path + * @param int $mode Sharing action mode + * @param array $args POST/GET parameters + * + * @return mixed Sharing response + * @throws Exception + */ + public function sharing($folder, $mode, $args = array()) + { + if ($mode == file_storage::SHARING_MODE_FORM) { + $form = array( + 'shares' => array( + 'title' => 'share.permissions', + 'form' => array( + 'user' => array( + 'title' => 'share.usergroup', + 'type' => 'input', + 'autocomplete' => 'user,group', + ), + 'right' => array( + 'title' => 'share.permission', + 'type' => 'select', + 'options' => array( + 'r' => 'share.readonly', + 'rw' => 'share.readwrite', + ), + ), + ), + 'extra_fields' => array( + 'type' => 'user', + 'id' => '', + ), + ), + 'download-link' => array( + 'title' => 'share.download-link', + 'label' => 'share.generate', + 'single' => true, + 'list_column' => 'link', + 'list_column_label' => 'share.link', + 'form' => array( + 'password' => array( + 'title' => 'share.password', + 'type' => 'password', + ), + 'expire' => array( + 'title' => 'share.expire', + 'placeholder' => 'share.expiredays', + 'type' => 'input', + ), + ), + 'extra_fields' => array( + 'id' => '', + ), + ), + 'upload-link' => array( + 'title' => 'share.upload-link', + 'label' => 'share.generate', + 'single' => true, + 'list_column' => 'link', + 'list_column_label' => 'share.link', + 'form' => array( + 'password' => array( + 'title' => 'share.password', + 'type' => 'password', + ), + ), + 'extra_fields' => array( + 'id' => '', + ), + ), + ); + + return $form; + } + + if ($mode == file_storage::SHARING_MODE_RIGHTS) { + if (!$this->init()) { + throw new Exception("Storage error. Unable to get shares of SeaFile folder/lib.", file_storage::ERROR); + } + + list($path, $repo_id) = $this->find_library($folder); + + $result = array(); + + if ($shares = $this->api->shared_item_list($repo_id, $path)) { + foreach ($shares as $share) { + if (!empty($share['group_info'])) { + $name = $share['group_info']['name']; + $name = $share['group_info']['id']; + } + else { + $name = $share['user_info']['name']; + $id = $share['user_info']['name']; + } + + $result[] = array( + 'mode' => 'shares', + 'type' => $share['share_type'], + 'right' => $share['permission'], + 'user' => $name, + 'id' => $id, + ); + } + } + + if ($links = $this->api->share_link_list($repo_id, $path)) { + foreach ($links as $link) { + $result[] = array( + 'mode' => 'download-link', + 'id' => $link['token'], + 'link' => $link['link'], + ); + } + } + + if ($links = $this->api->upload_link_list($repo_id, $path)) { + foreach ($links as $link) { + $result[] = array( + 'mode' => 'upload-link', + 'id' => $link['token'], + 'link' => $link['link'], + ); + } + } + + return $result; + } + + if ($mode == file_storage::SHARING_MODE_UPDATE) { + if (!$this->init()) { + throw new Exception("Storage error. Unable to update shares of SeaFile folder/lib.", file_storage::ERROR); + } + + list($path, $repo_id) = $this->find_library($folder); + + if ($args['mode'] == 'shares') { + switch ($args['action']) { + case 'submit': + $result = $this->api->shared_item_add($repo_id, $path, $args['right'], $args['type'], $args['user']); + break; + + case 'update': + $result = $this->api->shared_item_update($repo_id, $path, $args['right'], $args['type'], $args['id'] ?: $args['user']); + break; + + case 'delete': + $result = $this->api->shared_item_delete($repo_id, $path, $args['type'], $args['user']); + break; + } + } + else if ($args['mode'] == 'download-link') { + switch ($args['action']) { + case 'submit': + $result = $this->api->share_link_add($repo_id, $path, $args['password'], $args['expire']); + + if ($result) { + $result['id'] = $result['token']; + $result['mode'] = 'download-link'; + } + break; + + case 'delete': + $result = $this->api->share_link_delete($args['id']); + break; + } + } + else if ($args['mode'] == 'upload-link') { + switch ($args['action']) { + case 'submit': + $result = $this->api->upload_link_add($repo_id, $path, $args['password']); + + if ($result) { + $result['id'] = $result['token']; + $result['mode'] = 'upload-link'; + } + break; + + case 'delete': + $result = $this->api->upload_link_delete($args['id']); + break; + } + } + else { + throw new Exception("Invalid input.", file_storage::ERROR); + } +
View file
chwala-0.5.3.tar.gz/lib/drivers/webdav/webdav_file_storage.php -> chwala-0.5.4.tar.gz/lib/drivers/webdav/webdav_file_storage.php
Changed
@@ -917,6 +917,80 @@ } /** + * Sharing interface + * + * @param string $folder_name Name of a folder with full path + * @param int $mode Sharing action mode + * @param array $args POST/GET parameters + * + * @return mixed Sharing response + * @throws Exception + */ + public function sharing($folder, $mode, $args = array()) + { + // TODO + throw new Exception("Search not implemented", file_storage::ERROR_UNSUPPORTED); + } + + /** + * User/group search (autocompletion) + * + * @param string $search Search string + * @param int $mode Search mode + * + * @return array Users/Groups list + * @throws Exception + */ + public function autocomplete($search, $mode) + { + // TODO + throw new Exception("Search not implemented", file_storage::ERROR_UNSUPPORTED); + } + + /** + * Convert file/folder path into a global URI. + * + * @param string $path File/folder path + * + * @return string URI + * @throws Exception + */ + public function path2uri($path) + { + $base = preg_replace('|^[a-zA-Z]+://|', '', $this->config['baseuri']); + + return 'webdav://' . rawurlencode($this->config['username']) . '@' . $base + . '/' . file_utils::encode_path($path); + } + + /** + * Convert global URI into file/folder path. + * + * @param string $uri URI + * + * @return string File/folder path + * @throws Exception + */ + public function uri2path($uri) + { + if (!preg_match('|^webdav://([^@]+)@(.*)$|', $uri, $matches)) { + throw new Exception("Internal storage error. Unexpected data format.", file_storage::ERROR); + } + + $user = rawurldecode($matches[1]); + $base = preg_replace('|^[a-zA-Z]+://|', '', $this->config['baseuri']); + $uri = $matches[2]; + + if ($user != $this->config['username'] || strpos($uri, $base) !== 0) { + throw new Exception("Internal storage error. Unresolvable URI.", file_storage::ERROR); + } + + $uri = substr($matches[2], strlen($base) + 1); + + return file_utils::decode_path($uri); + } + + /** * Gets the relative URL of a resource * * @param string $url WebDAV URL @@ -976,49 +1050,6 @@ } /** - * Convert file/folder path into a global URI. - * - * @param string $path File/folder path - * - * @return string URI - * @throws Exception - */ - public function path2uri($path) - { - $base = preg_replace('|^[a-zA-Z]+://|', '', $this->config['baseuri']); - - return 'webdav://' . rawurlencode($this->config['username']) . '@' . $base - . '/' . file_utils::encode_path($path); - } - - /** - * Convert global URI into file/folder path. - * - * @param string $uri URI - * - * @return string File/folder path - * @throws Exception - */ - public function uri2path($uri) - { - if (!preg_match('|^webdav://([^@]+)@(.*)$|', $uri, $matches)) { - throw new Exception("Internal storage error. Unexpected data format.", file_storage::ERROR); - } - - $user = rawurldecode($matches[1]); - $base = preg_replace('|^[a-zA-Z]+://|', '', $this->config['baseuri']); - $uri = $matches[2]; - - if ($user != $this->config['username'] || strpos($uri, $base) !== 0) { - throw new Exception("Internal storage error. Unresolvable URI.", file_storage::ERROR); - } - - $uri = substr($matches[2], strlen($base) + 1); - - return file_utils::decode_path($uri); - } - - /** * Initializes file_locks object */ protected function init_lock_db()
View file
chwala-0.5.3.tar.gz/lib/file_api.php -> chwala-0.5.4.tar.gz/lib/file_api.php
Changed
@@ -188,9 +188,12 @@ $mem = memory_get_usage(); } - $request = ($this instanceof file_api_wopi ? 'wopi/' : '') - . $this->request - . (!empty($this->path) ? '/' . implode($this->path, '/') : ''); + $path = !empty($this->path) ? '/' . implode($this->path, '/') : ''; + $request = ($this instanceof file_api_wopi ? 'wopi/' : '') . $this->request; + + if ($path !== '' && substr_compare($this->request, $path, -1 * strlen($path), strlen($path), true) != 0) { + $request .= $path; + } $log = trim(sprintf('%s: %s %s', $this->method ?: $_SERVER['REQUEST_METHOD'],
View file
chwala-0.5.3.tar.gz/lib/file_api_core.php -> chwala-0.5.4.tar.gz/lib/file_api_core.php
Changed
@@ -24,7 +24,7 @@ class file_api_core extends file_locale { - const API_VERSION = 3; + const API_VERSION = 4; const ERROR_UNAUTHORIZED = 401; const ERROR_NOT_FOUND = 404; @@ -80,11 +80,12 @@ /** * Return supported/enabled external storage instances * - * @param bool $as_objects Return drivers as objects not config data + * @param bool $as_objects Return drivers as objects not config data + * @param array &$admin_drivers List of admin-configured drivers * * @return array List of storage drivers */ - public function get_drivers($as_objects = false) + public function get_drivers($as_objects = false, &$admin_drivers = null) { $rcube = rcube::get_instance(); $backend = $this->get_backend(); @@ -117,6 +118,8 @@ } } + $admin_drivers = array(); + if (empty($result) && !empty($preconf)) { foreach ((array) $preconf as $title => $item) { if (!in_array($title, $all)) { @@ -124,6 +127,8 @@ $item['admin'] = true; $result[] = $as_objects ? $this->get_driver_object($item) : $item; + + $admin_drivers[] = $title; } } } @@ -152,6 +157,11 @@ } if (empty($selected)) { + $rcube = rcube::get_instance(); + if ($rcube->config->get('fileapi_backend_storage_disabled')) { + throw new Exception("Failed to find a driver for specified folder/file.", self::ERROR_NOT_FOUND); + } + return array($this->get_backend(), $path); } @@ -218,7 +228,7 @@ { $rcube = rcube::get_instance(); $backend = $this->get_backend(); - $caps = array(); + $caps = array('VERSION' => self::API_VERSION); // check support for upload progress if (($progress_sec = $rcube->config->get('upload_progress')) @@ -246,6 +256,10 @@ $caps['WOPI'] = true; } + if ($rcube->config->get('fileapi_backend_storage_disabled')) { + $caps['NOROOT'] = true; + } + if (!$full) { return $caps; }
View file
chwala-0.5.3.tar.gz/lib/file_storage.php -> chwala-0.5.4.tar.gz/lib/file_storage.php
Changed
@@ -58,6 +58,16 @@ const ACL_READ = 1; const ACL_WRITE = 2; + // sharing interface modes + const SHARING_MODE_FORM = 1; + const SHARING_MODE_RIGHTS = 2; + const SHARING_MODE_UPDATE = 3; + + // search modes + const SEARCH_USER = 1; + const SEARCH_GROUP = 2; + + /** * Authenticates a user * @@ -349,7 +359,31 @@ public function quota($folder); /** + * Sharing interface + * + * @param string $folder_name Name of a folder with full path + * @param int $mode Sharing action mode + * @param array $args POST/GET parameters + * + * @return mixed Sharing response + * @throws Exception + */ + public function sharing($folder, $mode, $args = array()); + + /** + * User/group search (autocompletion) + * + * @param string $search Search string + * @param int $mode Search mode + * + * @return array Users/Groups list + * @throws Exception + */ + public function autocomplete($search, $mode); + + /** * Convert file/folder path into a global URI. + * Note: We're using self::SEPARATOR as a hierarchy delimiter * * @param string $path File/folder path * @@ -360,6 +394,7 @@ /** * Convert global URI into file/folder path. + * Note: We're using self::SEPARATOR as a hierarchy delimiter * * @param string $uri URI *
View file
chwala-0.5.3.tar.gz/lib/locale/en_US.php -> chwala-0.5.4.tar.gz/lib/locale/en_US.php
Changed
@@ -75,6 +75,20 @@ $LANG['search.in_all_folders'] = 'in all folders'; $LANG['search.in_current_folder'] = 'in current folder'; +$LANG['share.permissions'] = 'Permissions'; +$LANG['share.readonly'] = 'read-only'; +$LANG['share.readwrite'] = 'read-write'; +$LANG['share.admin'] = 'administrator'; +$LANG['share.usergroup'] = 'User or Group'; +$LANG['share.permission'] = 'Permission'; +$LANG['share.upload-link'] = 'Upload Link'; +$LANG['share.download-link'] = 'Download Link'; +$LANG['share.password'] = 'Password'; +$LANG['share.expire'] = 'Expiration'; +$LANG['share.expiredays'] = 'Expiration time in days'; +$LANG['share.generate'] = 'Generate'; +$LANG['share.link'] = 'Link'; + $LANG['size.B'] = 'B'; $LANG['size.KB'] = 'KB'; $LANG['size.MB'] = 'MB';
View file
chwala-0.5.3.tar.gz/lib/wopi/files.php -> chwala-0.5.4.tar.gz/lib/wopi/files.php
Changed
@@ -104,7 +104,7 @@ 'Version' => $info['modified'], 'OwnerId' => $info['owner'], 'UserId' => $info['user'], - 'UserFriendlyName' => $info['user_name'], + 'UserFriendlyName' => $info['user_name'] ?: preg_replace('/@.*$/', '', $info['user']), 'UserCanWrite' => empty($info['readonly']), 'PostMessageOrigin' => $info['origin'], // Tell the client we do not support PutRelativeFile yet @@ -114,9 +114,27 @@ 'HideExportOption' => true, 'HidePrintOption' => true, 'EnableOwnerTermination' => true, - // TODO: 'UserExtraInfo' => ['avatar' => 'http://url/to/user/avatar', 'mail' => 'user@server.com'] + 'WatermarkText' => '', // ?? + 'DisablePrint' => false, + 'DisableExport' => false, + 'DisableCopy' => false, + 'DisableInactiveMessages' => true, + 'DisableChangeTrackingRecord' => true, + 'DisableChangeTrackingShow' => true, + 'HideChangeTrackingControls' => true, + // TODO: 'UserExtraInfo' => ['avatar' => 'http://url/to/user/avatar', 'mail' => $info['user']] + 'UserExtraInfo' => array(), ); + if ($info['modified']) { + try { + $dt = new DateTime('@' . $info['modified'], new DateTimeZone('UTC')); + $result['LastModifiedTime'] = $dt->format('Y-m-dTH:i:s') . '.0000000Z'; + } + catch (Exception $e) { + } + } + return $result; }
View file
chwala-0.5.3.tar.gz/public_html/.htaccess -> chwala-0.5.4.tar.gz/public_html/.htaccess
Changed
@@ -2,4 +2,4 @@ php_flag display_errors Off php_flag log_errors On php_flag suhosin.session.encrypt Off -php_value error_log ../logs/errors +php_value error_log ../logs/errors.log
View file
chwala-0.5.3.tar.gz/public_html/api/.htaccess -> chwala-0.5.4.tar.gz/public_html/api/.htaccess
Changed
@@ -2,5 +2,5 @@ php_flag session.use_cookies Off php_flag display_errors Off php_flag log_errors On -php_value error_log ../../logs/errors +php_value error_log ../../logs/errors.log
View file
chwala-0.5.3.tar.gz/public_html/js/files_api.js -> chwala-0.5.4.tar.gz/public_html/js/files_api.js
Changed
@@ -72,7 +72,7 @@ /********************************************************/ // send a http POST request to the API service - this.post = function(action, data, func) + this.post = function(action, data, func, error_func) { var url = this.env.url + '?method=' + action; @@ -83,15 +83,15 @@ return $.ajax({ type: 'POST', url: url, data: JSON.stringify(data), dataType: 'json', contentType: 'application/json; charset=utf-8', - success: function(response) { if (typeof func == 'function') func(response); else ref[func](response); }, - error: function(o, status, err) { ref.http_error(o, status, err, data); }, + success: function(response) { if (typeof func == 'function') func(response, data); else ref[func](response, data); }, + error: function(o, status, err) { (error_func || ref.http_error)(o, status, err, data); }, cache: false, beforeSend: function(xmlhttp) { xmlhttp.setRequestHeader('X-Session-Token', ref.env.token); } }); }; // send a http GET request to the API service - this.get = function(action, data, func) + this.get = function(action, data, func, error_func) { var url = this.env.url; @@ -102,19 +102,19 @@ return $.ajax({ type: 'GET', url: url, data: data, dataType: 'json', - success: function(response) { if (typeof func == 'function') func(response); else ref[func](response); }, - error: function(o, status, err) { ref.http_error(o, status, err, data); }, + success: function(response) { if (typeof func == 'function') func(response, data); else ref[func](response, data); }, + error: function(o, status, err) { (error_func || ref.http_error)(o, status, err, data); }, cache: false, beforeSend: function(xmlhttp) { xmlhttp.setRequestHeader('X-Session-Token', ref.env.token); } }); }; // send request with auto-selection of POST/GET method - this.request = function(action, data, func) + this.request = function(action, data, func, error_func) { // Use POST for modification actions with probable big request size var method = /_(create|delete|move|copy|update|auth|subscribe|unsubscribe|invite|decline|request|accept|remove)$/.test(action) ? 'post' : 'get'; - return this[method](action, data, func); + return this[method](action, data, func, error_func); }; // handle HTTP request errors @@ -795,12 +795,9 @@ var color = value.Color; // make sure color is in css hex format - if (color) { - if ($.type(color) == 'string' && color.charAt(0) != '#') - color = '#' + color; - else if ($.type(color) == 'number') - color = ((color)>>>0).toString(16).slice(-6); - color = '#' + ("000000").substring(0, 6 - color.length) + color; + if (color && $.type(color) == 'number') { + color = ((color)>>>0).toString(16).slice(-6); + color = '#' + ("000000").substring(0, 6 - color.length) + color; } return { @@ -1186,6 +1183,24 @@ conf.invitationSaved(invitation); }; + this.domain_compare = function(origin, domain) + { + if (!origin && !domain) + return true; + + if (!origin || !domain) + return false; + + // Sometimes Collabora adds port to the URL + // We'll remove it for proper comparison + if (origin.match(/^https:\/\/(.*):443$/)) + origin = origin.replace(/:443$/, ''); + if (domain.match(/^https:\/\/(.*):443$/)) + domain = domain.replace(/:443$/, ''); + + return origin == domain; + }; + if (!conf) conf = {}; @@ -1204,7 +1219,7 @@ // Register 'message' event to receive messages from the editor iframe window.addEventListener('message', function(event) { - if (event.source == editor && event.origin == domain) { + if (event.source == editor && self.domain_compare(event.origin, domain)) { self.message_handler(event.data); } });
View file
chwala.dsc
Changed
@@ -2,7 +2,7 @@ Source: chwala Binary: chwala Architecture: all -Version: 0.5.3-0~kolab1 +Version: 0.5.4-0~kolab1 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>, Paul Klos <kolab@klos2day.nl> Homepage: http://kolab.org/about/chwala/ @@ -11,5 +11,5 @@ Package-List: roundcubemail deb web extra Files: - 00000000000000000000000000000000 0 chwala-0.5.3.tar.gz + 00000000000000000000000000000000 0 chwala-0.5.4.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +chwala (0.5.4-0~kolab1) unsable; urgency=low + + * Release version 0.5.4 + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabys.com> Fri, 26 Oct 2018 12:12:12 +0100 + chwala (0.5.3-0~kolab1) unsable; urgency=low * Release version 0.5.3
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.