diff --git a/lib/api/document.php b/lib/api/document.php index 3ff6fa8..a057b67 100644 --- a/lib/api/document.php +++ b/lib/api/document.php @@ -1,115 +1,117 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class file_api_document extends file_api_common { /** * Request handler */ public function handle() { if (empty($_GET['id'])) { throw new Exception("Missing document ID.", file_api_core::ERROR_CODE); } $method = $_SERVER['REQUEST_METHOD']; if ($method == 'POST' && !empty($_SERVER['HTTP_X_HTTP_METHOD'])) { $method = $_SERVER['HTTP_X_HTTP_METHOD']; } $file = $this->get_file_path($_GET['id']); if ($method == 'PUT' || $method == 'GET') { return $this->{'document_' . strtolower($method)}($file); } } /** * Get file path from manticore session identifier */ protected function get_file_path($id) { $manticore = new file_manticore($this->api); return $manticore->session_file($id); } /** * Update document file content */ protected function document_put($file) { list($driver, $path) = $this->api->get_driver($file); $length = rcube_utils::request_header('Content-Length'); $tmp_dir = unslashify($this->api->config->get('temp_dir')); $tmp_path = tempnam($tmp_dir, 'chwalaUpload'); // Create stream to copy input into a temp file $input = fopen('php://input', 'r'); $tmp_file = fopen($tmp_path, 'w'); if (!$input || !$tmp_file) { throw new Exception("Failed opening input or temp file stream.", file_api_core::ERROR_CODE); } // Create temp file from the input $copied = stream_copy_to_stream($input, $tmp_file); fclose($input); fclose($tmp_file); if ($copied < $length) { throw new Exception("Failed writing to temp file.", file_api_core::ERROR_CODE); } $file = array( 'path' => $tmp_path, 'type' => rcube_mime::file_content_type($tmp_path, $file), ); $driver->file_update($path, $file); // remove the temp file unlink($tmp_path); } /** * Return document file content */ protected function document_get($file) { list($driver, $path) = $this->api->get_driver($file); try { - $driver->file_get($path); + $params = array('force-type' => 'application/vnd.oasis.opendocument.text'); + + $driver->file_get($path, $params); } catch (Exception $e) { header("HTTP/1.0 " . file_api_core::ERROR_CODE . " " . $e->getMessage()); } exit; } } diff --git a/lib/api/folder_info.php b/lib/api/folder_info.php index c1667f6..e6a13b7 100644 --- a/lib/api/folder_info.php +++ b/lib/api/folder_info.php @@ -1,61 +1,61 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ 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); } $result = array( 'folder' => $this->args['folder'], ); if (!empty($this->args['rights']) && rcube_utils::get_boolean((string) $this->args['rights'])) { $result['rights'] = $this->folder_rights($this->args['folder']); } 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); + return $manticore->session_find($folder); } } diff --git a/lib/file_manticore.php b/lib/file_manticore.php index 47e1767..eca9a38 100644 --- a/lib/file_manticore.php +++ b/lib/file_manticore.php @@ -1,288 +1,294 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ /** * 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' => '', // @TODO: maybe set to a file path without extension? '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) { $session = $this->session_info($id); if (empty($session)) { throw new Exception("Document session ID not found.", file_api_core::ERROR_CODE); } $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( + $session = array( 'file' => $path, 'owner' => $data['user'], // @TODO: invitated?, last_modified? ); + + if ($data['user'] == $_SESSION['user']) { + $session['is_owner'] = true; + } + + $sessions[$row['id']] = $session; } } 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; } }