Page MenuHomePhorge

No OneTemporary

diff --git a/doc/SQL/mysql.initial.sql b/doc/SQL/mysql.initial.sql
index e294311..87c03aa 100644
--- a/doc/SQL/mysql.initial.sql
+++ b/doc/SQL/mysql.initial.sql
@@ -1,24 +1,23 @@
CREATE TABLE IF NOT EXISTS `chwala_locks` (
`uri` varchar(512) BINARY NOT NULL,
`owner` varchar(256),
`timeout` integer unsigned,
`expires` datetime DEFAULT NULL,
`token` varchar(256),
`scope` tinyint,
`depth` tinyint,
INDEX `uri_index` (`uri`, `depth`),
INDEX `expires_index` (`expires`),
INDEX `token_index` (`token`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
CREATE TABLE IF NOT EXISTS `chwala_sessions` (
`id` varchar(40) BINARY NOT NULL,
`uri` varchar(1024) BINARY NOT NULL,
- `expires` datetime DEFAULT NULL,
`data` mediumtext,
PRIMARY KEY (`id`),
UNIQUE INDEX `uri_index` (`uri`(255)),
INDEX `expires_index` (`expires`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
INSERT INTO `system` (`name`, `value`) VALUES ('chwala-version', '2015110400');
diff --git a/lib/api/common.php b/lib/api/common.php
index 4d5b3f6..8f7d5e7 100644
--- a/lib/api/common.php
+++ b/lib/api/common.php
@@ -1,143 +1,166 @@
<?php
/*
+--------------------------------------------------------------------------+
| This file is part of the Kolab File API |
| |
| Copyright (C) 2012-2014, 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_common
{
protected $api;
protected $rc;
protected $args = array();
public function __construct($api)
{
$this->rc = rcube::get_instance();
$this->api = $api;
}
/**
* Request handler
*/
public function handle()
{
// GET arguments
$this->args = &$_GET;
// POST arguments (JSON)
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$post = file_get_contents('php://input');
$this->args += (array) json_decode($post, true);
unset($post);
}
// disable script execution time limit, so we can handle big files
@set_time_limit(0);
}
/**
* File uploads handler
*/
protected function upload()
{
$files = array();
if (is_array($_FILES['file']['tmp_name'])) {
foreach ($_FILES['file']['tmp_name'] as $i => $filepath) {
if ($err = $_FILES['file']['error'][$i]) {
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
$maxsize = ini_get('upload_max_filesize');
$maxsize = $this->show_bytes(parse_bytes($maxsize));
throw new Exception("Maximum file size ($maxsize) exceeded", file_api_core::ERROR_CODE);
}
throw new Exception("File upload failed", file_api_core::ERROR_CODE);
}
$files[] = array(
'path' => $filepath,
'name' => $_FILES['file']['name'][$i],
'size' => filesize($filepath),
'type' => rcube_mime::file_content_type($filepath, $_FILES['file']['name'][$i], $_FILES['file']['type']),
);
}
}
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// if filesize exceeds post_max_size then $_FILES array is empty,
if ($maxsize = ini_get('post_max_size')) {
$maxsize = $this->show_bytes(parse_bytes($maxsize));
throw new Exception("Maximum file size ($maxsize) exceeded", file_api_core::ERROR_CODE);
}
throw new Exception("File upload failed", file_api_core::ERROR_CODE);
}
return $files;
}
/**
* Return built-in viewer opbject for specified mimetype
*
* @return object Viewer object
*/
protected function find_viewer($mimetype)
{
$dir = RCUBE_INSTALL_PATH . 'lib/viewers';
if ($handle = opendir($dir)) {
while (false !== ($file = readdir($handle))) {
if (preg_match('/^([a-z0-9_]+)\.php$/i', $file, $matches)) {
include_once $dir . '/' . $file;
$class = 'file_viewer_' . $matches[1];
$viewer = new $class($this->api);
if ($viewer->supports($mimetype)) {
return $viewer;
}
}
}
closedir($handle);
}
}
/**
* Parse driver metadata information
*/
protected function parse_metadata($metadata, $default = false)
{
if ($default) {
unset($metadata['form']);
$metadata['name'] .= ' (' . $this->api->translate('localstorage') . ')';
}
// localize form labels
foreach ($metadata['form'] as $key => $val) {
$label = $this->api->translate('form.' . $val);
if (strpos($label, 'form.') !== 0) {
$metadata['form'][$key] = $label;
}
}
return $metadata;
}
+
+ /**
+ * Get folder rights
+ */
+ protected function folder_rights($folder)
+ {
+ list($driver, $path) = $this->api->get_driver($folder);
+
+ $rights = $driver->folder_rights($path);
+ $result = array();
+ $map = array(
+ file_storage::ACL_READ => 'read',
+ file_storage::ACL_WRITE => 'write',
+ );
+
+ foreach ($map as $key => $value) {
+ if ($rights & $key) {
+ $result[] = $value;
+ }
+ }
+
+ return $result;
+ }
}
diff --git a/lib/api/folder_rights.php b/lib/api/folder_info.php
similarity index 73%
rename from lib/api/folder_rights.php
rename to lib/api/folder_info.php
index 9894f93..c1667f6 100644
--- a/lib/api/folder_rights.php
+++ b/lib/api/folder_info.php
@@ -1,58 +1,61 @@
<?php
/**
+--------------------------------------------------------------------------+
| This file is part of the Kolab File API |
| |
| Copyright (C) 2012-2015, 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_folder_rights extends file_api_common
+class file_api_folder_info 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']);
-
- $rights = $driver->folder_rights($path);
- $result = array();
- $map = array(
- file_storage::ACL_READ => 'read',
- file_storage::ACL_WRITE => 'write',
+ $result = array(
+ 'folder' => $this->args['folder'],
);
- foreach ($map as $key => $value) {
- if ($rights & $key) {
- $result[] = $value;
- }
+ if (!empty($this->args['rights']) && rcube_utils::get_boolean((string) $this->args['rights'])) {
+ $result['rights'] = $this->folder_rights($this->args['folder']);
}
- return array(
- 'folder' => $this->args['folder'],
- 'rights' => $result,
- );
+ if (!empty($this->args['sessions']) && rcube_utils::get_boolean((string) $this->args['sessions'])) {
+ $result['sessions'] = $this->folder_sessions($this->args['folder']);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get editing sessions
+ */
+ protected function folder_sessions($folder)
+ {
+ $manticore = new file_manticore($this->api);
+ return $manticore->sessions_find($folder);
}
}
diff --git a/lib/file_api_lib.php b/lib/file_api_lib.php
index bda3f20..3747141 100644
--- a/lib/file_api_lib.php
+++ b/lib/file_api_lib.php
@@ -1,188 +1,195 @@
<?php
/*
+--------------------------------------------------------------------------+
| This file is part of the Kolab File API |
| |
| Copyright (C) 2012-2014, 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> |
+--------------------------------------------------------------------------+
*/
/**
* This class gives access to Chwala API as a library
*/
class file_api_lib extends file_api_core
{
/**
* API methods handler
*/
public function __call($name, $arguments)
{
$this->init();
switch ($name) {
case 'configure':
foreach (array_keys($this->env) as $name) {
if (isset($arguments[0][$name])) {
$this->env[$name] = $arguments[0][$name];
}
}
return $this->env;
case 'mimetypes':
return $this->supported_mimetypes();
case 'file_list':
$args = array(
'folder' => $arguments[0],
);
break;
case 'file_create':
case 'file_update':
$args = array(
'file' => $arguments[0],
'path' => $arguments[1]['path'],
'content' => $arguments[1]['content'],
'content-type' => $arguments[1]['type'],
);
break;
case 'file_delete':
case 'file_info':
$args = array(
'file' => $arguments[0],
);
break;
case 'file_copy':
case 'file_move':
$args = array(
'file' => array($arguments[0] => $arguments[1]),
);
break;
case 'file_get':
// override default action, we need only to support
// writes to file handle
list($driver, $path) = $this->get_driver($arguments[0]);
$driver->file_get($path, $arguments[1], $arguments[2]);
return;
case 'folder_list':
// no arguments
$args = array();
break;
case 'folder_create':
case 'folder_subscribe':
case 'folder_unsubscribe':
case 'folder_delete':
- case 'folder_rights':
$args = array(
'folder' => $arguments[0],
);
break;
+ case 'folder_info':
+ $args = array(
+ 'folder' => $arguments[0],
+ 'rights' => 1,
+ 'sessions' => 1,
+ );
+ break;
+
case 'folder_move':
$args = array(
'folder' => $arguments[0],
'new' => $arguments[1],
);
break;
case 'lock_create':
case 'lock_delete':
$args = $arguments[1];
$args['uri'] = $arguments[0];
break;
case 'lock_list':
$args = array(
'uri' => $arguments[0],
'child_locks' => $arguments[1],
);
break;
default:
throw new Exception("Invalid method name", \file_storage::ERROR_UNSUPPORTED);
}
require_once __DIR__ . "/api/$name.php";
$class = "file_api_$name";
$handler = new $class($this, $args);
return $handler->handle();
}
/**
* Configure environment (this is to be overriden by implementation class)
*/
protected function init()
{
}
}
/**
* Common handler class, from which action handler classes inherit
*/
class file_api_common
{
protected $api;
protected $rc;
protected $args;
public function __construct($api, $args)
{
$this->rc = rcube::get_instance();
$this->api = $api;
$this->args = $args;
}
/**
* Request handler
*/
public function handle()
{
// disable script execution time limit, so we can handle big files
@set_time_limit(0);
}
/**
* Parse driver metadata information
*/
protected function parse_metadata($metadata, $default = false)
{
if ($default) {
unset($metadata['form']);
$metadata['name'] .= ' (' . $this->api->translate('localstorage') . ')';
}
// localize form labels
foreach ($metadata['form'] as $key => $val) {
$label = $this->api->translate('form.' . $val);
if (strpos($label, 'form.') !== 0) {
$metadata['form'][$key] = $label;
}
}
return $metadata;
}
}
diff --git a/lib/file_manticore.php b/lib/file_manticore.php
index 9e33c56..85a4110 100644
--- a/lib/file_manticore.php
+++ b/lib/file_manticore.php
@@ -1,246 +1,288 @@
<?php
/**
+--------------------------------------------------------------------------+
| This file is part of the Kolab File API |
| |
| Copyright (C) 2012-2015, 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> |
+--------------------------------------------------------------------------+
*/
/**
* Document editing sessions handling
*/
class file_manticore
{
protected $api;
protected $rc;
protected $request;
protected $table = 'chwala_sessions';
/**
* Class constructor
*
* @param file_api Chwala API app instance
*/
public function __construct($api)
{
$this->rc = rcube::get_instance();
$this->api = $api;
}
/**
* Return viewer URI for specified file. This creates
* a new collaborative editing session when needed
*
* @param string $file File path
*
* @return string Manticore URI
* @throws Exception
*/
public function viewer_uri($file)
{
list($driver, $path) = $this->api->get_driver($file);
$backend = $this->api->get_backend();
$uri = $driver->path2uri($path);
$id = rcube_utils::bin2ascii(md5(time() . $uri, true));
$data = array(
'user' => $_SESSION['user'],
);
// @TODO: check if session exists and is valid (?)
// we'll store user credentials if the file comes from
// an external source that requires authentication
if ($backend != $driver) {
$auth = $driver->auth_info();
$auth['password'] = $this->rc->encrypt($auth['password']);
$data['auth_info'] = $auth;
}
// Do this before starting the session in Manticore,
// it will immediately call api/document to get the file body
$res = $this->session_create($id, $uri, $data);
if (!$res) {
throw new Exception("Failed creating document editing session", file_api_core::ERROR_CODE);
}
// get filename
$path = explode(file_storage::SEPARATOR, $path);
$filename = $path[count($path)-1];
// create the session in Manticore
$req = $this->get_request();
$res = $req->session_create(array(
'id' => $id,
'title' => $filename,
'access' => array(
array(
'identity' => $data['user'],
'permission' => 'write',
),
),
));
if (!$res) {
$this->session_delete($id);
throw new Exception("Failed creating document editing session", file_api_core::ERROR_CODE);
}
return $this->frame_uri($id);
}
/**
* Get file path (not URI) from session.
*
* @param string $id Session ID
*
* @return string File path
* @throws Exception
*/
public function session_file($id)
{
- $backend = $this->api->get_backend();
$session = $this->session_info($id);
if (empty($session)) {
throw new Exception("Document session ID not found.", file_api_core::ERROR_CODE);
}
- try {
- return $backend->uri2path($session['uri']);
- }
- catch (Exception $e) {
- // do nothing
- }
-
- foreach ($this->api->get_drivers(true) as $driver) {
- try {
- $path = $driver->uri2path($session['uri']);
- $title = $driver->title();
-
- if ($title) {
- $path = $title . file_storage::SEPARATOR . $path;
- }
-
- return $path;
- }
- catch (Exception $e) {
- // do nothing
- }
- }
+ $path = $this->uri2path($session['uri']);
if (empty($path)) {
throw new Exception("Document session ID not found.", file_api_core::ERROR_CODE);
}
+
+ return $path;
}
/**
* Get editing session info
*/
public function session_info($id)
{
$db = $this->rc->get_dbh();
$result = $db->query("SELECT * FROM `{$this->table}`"
. " WHERE `id` = ?", $id);
if ($row = $db->fetch_assoc($result)) {
$row['data'] = json_decode($row['data'], true);
return $row;
}
}
+ /**
+ * Find editing sessions for specified path
+ */
+ public function session_find($path)
+ {
+ // create an URI for specified path
+ list($driver, $path) = $this->api->get_driver($path);
+
+ $uri = trim($driver->path2uri($path), '/') . '/';
+
+ // get existing sessions
+ $db = $this->rc->get_dbh();
+ $sessions = array();
+ $result = $db->query("SELECT * FROM `{$this->table}`"
+ . " WHERE `uri` LIKE '" . $db->escape($uri) . "%'");
+
+ if ($row = $db->fetch_assoc($result)) {
+ if ($path = $this->uri2path($row['uri'])) {
+ $data = json_decode($row['data'], true);
+
+ $sessions[$row['id']] = array(
+ 'file' => $path,
+ 'owner' => $data['user'],
+ // @TODO: invitated?, last_modified?
+ );
+ }
+ }
+
+ return $sessions;
+ }
+
/**
* Create editing session
*/
protected function session_create($id, $uri, $data)
{
$db = $this->rc->get_dbh();
$result = $db->query("INSERT INTO `{$this->table}`"
. " (`id`, `uri`, `data`) VALUES (?, ?, ?)",
$id, $uri, json_encode($data));
return $db->affected_rows($result) > 0;
}
/**
* Delete editing session
*/
protected function session_delete($id)
{
$db = $this->rc->get_dbh();
$result = $db->query("DELETE FROM `{$this->table}`"
. " WHERE `id` = ?", $id);
return $db->affected_rows($result) > 0;
}
/**
* Generate URI of Manticore editing session
*/
protected function frame_uri($id)
{
$base_url = rtrim($this->rc->config->get('fileapi_manticore'), ' /');
return $base_url . '/document/' . $id . '/' . $_SESSION['manticore_token'];
}
+ /**
+ * Get file path from the URI
+ */
+ protected function uri2path($uri)
+ {
+ $backend = $this->api->get_backend();
+
+ try {
+ return $backend->uri2path($uri);
+ }
+ catch (Exception $e) {
+ // do nothing
+ }
+
+ foreach ($this->api->get_drivers(true) as $driver) {
+ try {
+ $path = $driver->uri2path($uri);
+ $title = $driver->title();
+
+ if ($title) {
+ $path = $title . file_storage::SEPARATOR . $path;
+ }
+
+ return $path;
+ }
+ catch (Exception $e) {
+ // do nothing
+ }
+ }
+ }
+
/**
* Return Manticore user/session info
*/
public function user_info()
{
$req = $this->get_request();
$res = $req->get('api/users/me');
return $res->get();
}
/**
* Initialize Manticore API request handler
*/
protected function get_request()
{
if (!$this->request) {
$uri = rcube_utils::resolve_url($this->rc->config->get('fileapi_manticore'));
$this->request = new file_manticore_api($uri);
// Use stored session token, check if it's still valid
if ($_SESSION['manticore_token']) {
$is_valid = $this->request->set_session_token($_SESSION['manticore_token'], true);
if ($is_valid) {
return $this->request;
}
}
$backend = $this->api->get_backend();
$auth = $backend->auth_info();
$_SESSION['manticore_token'] = $this->request->login($auth['username'], $auth['password']);
if (empty($_SESSION['manticore_token'])) {
throw new Exception("Unable to login to Manticore server.", file_api_core::ERROR_CODE);
}
}
return $this->request;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 10, 3:50 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
197165
Default Alt Text
(26 KB)

Event Timeline