Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F257118
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
26 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Jun 10, 3:50 PM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
197165
Default Alt Text
(26 KB)
Attached To
Mode
R26 chwala
Attached
Detach File
Event Timeline
Log In to Comment