From e5403e6fd99d1a813ec7176b3c0fad14c1e2c35a Mon Sep 17 00:00:00 2001 From: Megan Watson Date: Wed, 10 Feb 2010 13:54:34 +0200 Subject: [PATCH] Updated webservices to V3. Added download by version, get metadata by version, shortcuts. PT: 2294845 --- config/dmsDefaults.php | 2 +- ktapi/KTAPIConstants.inc.php | 21 +++++++++++---------- ktapi/KTAPIDocument.inc.php | 47 ++++++++++++++++++++++++++++++++++++++++++----- ktapi/ktapi.inc.php | 16 ++++++++++++++++ ktwebservice/KTDownloadManager.inc.php | 71 +++++++++++++++++++++++++++++++++++------------------------------------ ktwebservice/download.php | 4 ++-- ktwebservice/webservice.php | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- lib/documentmanagement/Document.inc | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- lib/documentmanagement/documentmetadataversion.inc.php | 38 +++++++++++++++++++------------------- lib/storage/ondiskhashedstoragemanager.inc.php | 16 +++++++++++++++- sql/mysql/install/structure.sql | 4 ++-- sql/mysql/upgrade/3.7.0.4/download_files.sql | 1 + tests/runtests.php | 6 +++--- tests/webservices/testSoap.php | 727 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------- 14 files changed, 943 insertions(+), 145 deletions(-) create mode 100644 sql/mysql/upgrade/3.7.0.4/download_files.sql diff --git a/config/dmsDefaults.php b/config/dmsDefaults.php index e0033d7..d0c13e5 100644 --- a/config/dmsDefaults.php +++ b/config/dmsDefaults.php @@ -47,7 +47,7 @@ if (defined('DMS_DEFAULTS_INCLUDED')) } define('DMS_DEFAULTS_INCLUDED',1); -define('LATEST_WEBSERVICE_VERSION',2); +define('LATEST_WEBSERVICE_VERSION',3); if (function_exists('apd_set_pprof_trace')) { diff --git a/ktapi/KTAPIConstants.inc.php b/ktapi/KTAPIConstants.inc.php index 29ef5ff..e0c7409 100644 --- a/ktapi/KTAPIConstants.inc.php +++ b/ktapi/KTAPIConstants.inc.php @@ -5,32 +5,32 @@ * KnowledgeTree Community Edition * Document Management Made Simple * Copyright (C) 2008, 2009, 2010 KnowledgeTree Inc. - * - * + * + * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 3 as published by the * Free Software Foundation. - * + * * 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 General Public License for more * details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, + * + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, * California 94120-7775, or email info@knowledgetree.com. - * + * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU General Public License version 3. - * + * * In accordance with Section 7(b) of the GNU General Public License version 3, * these Appropriate Legal Notices must retain the display of the "Powered by - * KnowledgeTree" logo and retain the original copyright notice. If the display of the + * KnowledgeTree" logo and retain the original copyright notice. If the display of the * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices - * must display the words "Powered by KnowledgeTree" and retain the original + * must display the words "Powered by KnowledgeTree" and retain the original * copyright notice. * Contributor( s): ______________________________________ */ @@ -53,6 +53,7 @@ define('KTAPI_ERROR_SESSION_INVALID', 'The session could not be resolved.'); define('KTAPI_ERROR_PERMISSION_INVALID', 'The permission could not be resolved.'); define('KTAPI_ERROR_FOLDER_INVALID', 'The folder could not be resolved.'); define('KTAPI_ERROR_DOCUMENT_INVALID', 'The document could not be resolved.'); +define('KTAPI_ERROR_VERSION_INVALID', 'The document version could not be resolved.'); define('KTAPI_ERROR_USER_INVALID', 'The user could not be resolved.'); define('KTAPI_ERROR_KTAPI_INVALID', 'The ktapi could not be resolved.'); define('KTAPI_ERROR_INSUFFICIENT_PERMISSIONS', 'The user does not have sufficient permissions to access the resource.'); diff --git a/ktapi/KTAPIDocument.inc.php b/ktapi/KTAPIDocument.inc.php index 148cf2b..5149704 100644 --- a/ktapi/KTAPIDocument.inc.php +++ b/ktapi/KTAPIDocument.inc.php @@ -91,16 +91,17 @@ class KTAPI_Document extends KTAPI_FolderItem } /** - * This is used to get a document based on document id. + * This is used to get a document based on document id. Or a version of the document based on the metadata version id * * @author KnowledgeTree Team * @static * @access public * @param KTAPI $ktapi The ktapi object * @param int $documentid The document id + * @param int $iMetadataVersionId Optional. The metadata version id * @return KTAPI_Document The document object */ - function &get(&$ktapi, $documentid) + function &get(&$ktapi, $documentid, $iMetadataVersionId = null) { assert(!is_null($ktapi)); assert(is_a($ktapi, 'KTAPI')); @@ -108,7 +109,7 @@ class KTAPI_Document extends KTAPI_FolderItem $documentid += 0; - $document = &Document::get($documentid); + $document = &Document::get($documentid, $iMetadataVersionId); if (is_null($document) || PEAR::isError($document)) { return new KTAPI_Error(KTAPI_ERROR_DOCUMENT_INVALID,$document ); @@ -137,6 +138,30 @@ class KTAPI_Document extends KTAPI_FolderItem } /** + * This is used to get a document based on the document id and the metadata version + * + * @author KnowledgeTree Team + * @static + * @access public + * @param KTAPI $ktapi The ktapi object + * @param int $documentid The document id + * @param int $metadataVersion The metadata version (0,1,2) + * @return KTAPI_Document The document object + */ + function &get_by_metadata_version(&$ktapi, $documentid, $metadataVersion) + { + // get the metadata version id + $iMetadataVersionId = Document::getMetadataVersionIdFromVersion($documentid, $metadataVersion); + if (is_null($iMetadataVersionId) || PEAR::isError($iMetadataVersionId)) + { + return new KTAPI_Error(KTAPI_ERROR_VERSION_INVALID, $iMetadataVersionId ); + } + + // get the KTAPI_Document object + return self::get($ktapi, $documentid, $iMetadataVersionId); + } + + /** * Checks if a document has been deleted * * @author KnowledgeTree Team @@ -2137,13 +2162,14 @@ class KTAPI_Document extends KTAPI_FolderItem * @author KnowledgeTree Team * @access public */ - function download() + function download($version = null) { $storage =& KTStorageManagerUtil::getSingleton(); $options = array(); + $comment = (!is_null($version)) ? 'Document version '.$version.' downloaded' : 'Document downloaded'; $oDocumentTransaction = new DocumentTransaction($this->document, 'Document downloaded', 'ktcore.transactions.download', $aOptions); - $oDocumentTransaction->create(); + return $oDocumentTransaction->create(); } /** @@ -2241,6 +2267,17 @@ class KTAPI_Document extends KTAPI_FolderItem } /** + * Get the content version id using the document (content) version - major/minor version + * + * @param string $version + * @return int + */ + function get_content_version_id_from_version($version) + { + return $this->document->getContentVersionIdFromVersion($version); + } + + /** * This expunges a document from the system. * * diff --git a/ktapi/ktapi.inc.php b/ktapi/ktapi.inc.php index 882600a..f8a6b96 100644 --- a/ktapi/ktapi.inc.php +++ b/ktapi/ktapi.inc.php @@ -870,6 +870,22 @@ class KTAPI } /** + * This returns a refererence to a document based on document id. + * + * @author KnowledgeTree Team + * @access public + * @param integer $documentid The document id + * @param integer $metadataVersion The metadata version of the document (not the id) + * @return object $document The KTAPI_Document object + */ + public function &get_document_by_metadata_version($documentid, $metadataVersion) + { + // Get the document using the metadata version + $document = KTAPI_Document::get_by_metadata_version($this, $documentid, $metadataVersion); + return $document; + } + + /** * This returns a document type id based on the name or an error object. * * @author KnowledgeTree Team diff --git a/ktwebservice/KTDownloadManager.inc.php b/ktwebservice/KTDownloadManager.inc.php index 43beb07..5d32657 100644 --- a/ktwebservice/KTDownloadManager.inc.php +++ b/ktwebservice/KTDownloadManager.inc.php @@ -9,7 +9,7 @@ * KnowledgeTree Community Edition * Document Management Made Simple * Copyright (C) 2008, 2009, 2010 KnowledgeTree Inc. - * + * * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 3 as published by the @@ -76,44 +76,41 @@ class KTDownloadManager { $this->session = $session; } - + /** * This returns * * @access public * @param KTAPI_Document $document + * @param int $content_version_id Optional. The id of the requested content version * @return string */ - function allow_download($document, $content_version = null, $multipart = false) { + function allow_download($document, $content_version_id = null, $multipart = false) { assert ( ! is_null ( $document ) ); - - $content_version = 0; + $filesize = 0; - + if ($document instanceof KTAPI_Document) { $doc_id = $document->documentid; - $content_version = $document->document->getContentVersionId (); + //$content_version_id = (is_numeric($content_version_id)) ? $content_version_id : $document->document->getContentVersionId(); $filesize = $document->document->getFileSize (); } else if ($document instanceof Document || $document instanceof DocumentProxy) { $doc_id = $document->getId (); - $content_version = $document->getContentVersionId (); + //$content_version_id = (is_numeric($content_version_id)) ? $content_version_id : $document->getContentVersionId(); $filesize = $document->getFileSize (); } else if (is_numeric ( $document )) { $doc_id = $document; } else die ( 'gracefully' ); - - //assert(is_a($document, 'KTAPI_Document')); - - - $hash = sha1 ( "$doc_id $this->session $this->random" ); - - $id = DBUtil::autoInsert ( 'download_files', array ('document_id' => $doc_id, 'session' => $this->session, 'download_date' => date ( 'Y-m-d H:i:s' ), 'content_version' => $content_version, 'filesize' => $filesize, 'hash' => $hash ), array ('noid' => true ) ); - - return $multipart?$this->build_multipart_url( $hash, $doc_id ):$this->build_url ( $hash, $doc_id ); + + $hash = sha1 ( "$doc_id $content_version_id $this->session $this->random" ); + + $id = DBUtil::autoInsert ( 'download_files', array ('document_id' => $doc_id, 'session' => $this->session, 'download_date' => date ( 'Y-m-d H:i:s' ), 'content_version' => $content_version_id, 'filesize' => $filesize, 'hash' => $hash ), array ('noid' => true ) ); + + return $multipart ? $this->build_multipart_url( $hash, $doc_id ) : $this->build_url ( $hash, $doc_id ); } - - + + /** * This returns the url used to download a document. * @@ -125,21 +122,24 @@ class KTDownloadManager function build_url($hash, $documentid) { return $this->download_url . "?code=$hash&d=$documentid&u=$this->session"; } - + function build_multipart_url($hash, $documentId) { -// return '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'; return $this->multipart_download_url . "?code=$hash&d=$documentId&u=$this->session"; } - /** * This starts a download. * * @access public + * + * @param int $document_id + * @param string $hash + * @param string $apptype + * @return mixed */ - function download($document_id, $hash, $version = null, $apptype = 'ws') + function download($document_id, $hash, $apptype = 'ws') { - $sql = "SELECT 1 FROM download_files WHERE hash=? AND session=? AND document_id=?"; + $sql = "SELECT content_version FROM download_files WHERE hash=? AND session=? AND document_id=?"; $rows = DBUtil::getResultArray(array($sql, array($hash, $this->session, $document_id))); if (PEAR::isError($rows)) { @@ -151,11 +151,14 @@ class KTDownloadManager return new PEAR_Error('Invalid session.'); } + // Get the content version id + $content_version_id = $rows[0]['content_version']; + // If document is being downloaded by an external user bypass the session checking $check = strstr($this->session, 'ktext_'.$document_id); if($check == 0 && $check !== false){ // Use external download function - return $this->download_ext($document_id, $hash, $version = null); + return $this->download_ext($document_id, $hash, $content_version_id); } $storage =& KTStorageManagerUtil::getSingleton(); @@ -173,11 +176,9 @@ class KTDownloadManager return $document; } - if (!empty($version)) + if (!empty($content_version_id)) { - $version = KTDocumentContentVersion::get($version); - - $res = $storage->downloadVersion($document->document, $version); + $res = $storage->downloadVersion($document->document, $content_version_id); } else { @@ -193,8 +194,8 @@ class KTDownloadManager return true; } - - function download_ext($document_id, $hash, $version = null) + + function download_ext($document_id, $hash, $content_version_id = null) { $storage =& KTStorageManagerUtil::getSingleton(); $document = Document::get($document_id); @@ -203,11 +204,9 @@ class KTDownloadManager return $document; } - if (!empty($version)) + if (!empty($content_version_id)) { - $version = KTDocumentContentVersion::get($version); - - $res = $storage->downloadVersion($document, $version); + $res = $storage->downloadVersion($document, $content_version_id); } else { @@ -237,4 +236,4 @@ class KTDownloadManager DBUtil::runQuery($sql); } } -?> +?> \ No newline at end of file diff --git a/ktwebservice/download.php b/ktwebservice/download.php index 05d413b..6965e84 100644 --- a/ktwebservice/download.php +++ b/ktwebservice/download.php @@ -7,7 +7,7 @@ * KnowledgeTree Community Edition * Document Management Made Simple * Copyright (C) 2008, 2009, 2010 KnowledgeTree Inc. - * + * * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 3 as published by the @@ -73,7 +73,7 @@ require_once('KTDownloadManager.inc.php'); $download_manager = new KTDownloadManager(); $download_manager->set_session($session); -$response = $download_manager->download($document_id, $hash, null, $apptype); +$response = $download_manager->download($document_id, $hash, $apptype); if (PEAR::isError($response)) { $msg = urlencode($response->getMessage()); diff --git a/ktwebservice/webservice.php b/ktwebservice/webservice.php index 70a9926..5445c04 100644 --- a/ktwebservice/webservice.php +++ b/ktwebservice/webservice.php @@ -60,8 +60,6 @@ if (defined('HAS_SEARCH_FUNCTIONALITY')) require_once(KT_DIR . '/search2/search/search.inc.php'); } -// TODO: allow downloading of metadata versions -// TODO: allow downloading of document versions // TODO: chunking search results // TODO: add basic permissions management - add permissions to folder based on user/groups // TODO: refactor!!! download manager, split this file into a few smaller ones, etc @@ -72,7 +70,7 @@ if (defined('HAS_SEARCH_FUNCTIONALITY')) // TODO: ktwsapi/php must be made compatible with v2/v3 // TODO: subscriptions/notifications -// NOTE: some features are not implemented yet. most expected for v3. e.g. oem_document_no, custom_document_no, download($version)., get_metadata($version) +// NOTE: some features are not implemented yet. most expected for v3. e.g. oem_document_no, custom_document_no // Status Codes as defined in the specification. @@ -97,7 +95,7 @@ define('KTWS_ERR_DB_PROBLEM', 99); if (!defined('LATEST_WEBSERVICE_VERSION')) { - define('LATEST_WEBSERVICE_VERSION', 2); + define('LATEST_WEBSERVICE_VERSION', 3); } function bool2str($bool) @@ -2944,12 +2942,13 @@ class KTWebService * * @param string $session_id * @param int $document_id + * @param string $version The document (content) version - "major version" . "minor version" * @return kt_response. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_DOCUMENT or KTWS_SUCCESS */ function download_document($session_id, $document_id, $version=null) { - $this->debug("download_document('$session_id',$document_id)"); + $this->debug("download_document('$session_id',$document_id, '$version')"); $kt = &$this->get_ktapi($session_id ); if (is_array($kt)) @@ -2968,11 +2967,23 @@ class KTWebService return new SOAP_Value('return',"{urn:$this->namespace}kt_response", $response); } - $result = $document->download(); + $content_version_id = null; + if(!empty($version)){ + // Get the content version id for the given document version + $content_version_id = $document->get_content_version_id_from_version($version); + if (PEAR::isError($content_version_id)) + { + $response['message'] = $result->getMessage(); + $this->debug("download_document - cannot get version $version - " . $result->getMessage(), $session_id); + return new SOAP_Value('return',"{urn:$this->namespace}kt_response", $response); + } + } + + $result = $document->download($version); if (PEAR::isError($result)) { $response['message'] = $result->getMessage(); - $this->debug("download_document - cannot download - " . $result->getMessage(), $session_id); + $this->debug("download_document - cannot download (version $version) - " . $result->getMessage(), $session_id); return new SOAP_Value('return',"{urn:$this->namespace}kt_response", $response); } @@ -2980,7 +2991,7 @@ class KTWebService $download_manager = new KTDownloadManager(); $download_manager->set_session($session->session); $download_manager->cleanup(); - $url = $download_manager->allow_download($document); + $url = $download_manager->allow_download($document, $content_version_id); $response['status_code'] = KTWS_SUCCESS; $response['message'] = $url; @@ -3016,7 +3027,19 @@ class KTWebService return new SOAP_Value('return',"{urn:$this->namespace}kt_response", $response); } - $result = $document->download(); + $content_version_id = null; + if(!empty($version)){ + // Get the content version id for the given document version + $content_version_id = $document->get_content_version_id_from_version($version); + if (PEAR::isError($content_version_id)) + { + $response['message'] = $result->getMessage(); + $this->debug("download_document - cannot get version $version - " . $result->getMessage(), $session_id); + return new SOAP_Value('return',"{urn:$this->namespace}kt_response", $response); + } + } + + $result = $document->download($version); if (PEAR::isError($result)) { $response['message'] = $result->getMessage(); @@ -3024,24 +3047,33 @@ class KTWebService return new SOAP_Value('return',"{urn:$this->namespace}kt_response", $response); } - $content=''; + $content = ''; + $oStorage =& KTStorageManagerUtil::getSingleton(); - $document = $document->document; + // for a specified version + if(is_numeric($content_version_id)){ + $filename = $oStorage->temporaryFileForVersion($content_version_id); - $oStorage =& KTStorageManagerUtil::getSingleton(); - $filename = $oStorage->temporaryFile($document); - - $fp=fopen($filename,'rb'); - if ($fp === false) - { + if(!$filename){ $response['message'] = 'The file is not in the storage system. Please contact an administrator!'; - $this->debug("download_small_document - cannot write $filename", $session_id); + $this->debug("download_small_document - $filename cannot be found in the storage system", $session_id); return new SOAP_Value('return',"{urn:$this->namespace}kt_response", $response); - } - $content = fread($fp, filesize($filename)); - fclose($fp); - $content = base64_encode($content); + } + }else{ + $document = $document->document; + $filename = $oStorage->temporaryFile($document); + } + $fp=fopen($filename,'rb'); + if ($fp === false) + { + $response['message'] = 'The file is not in the storage system. Please contact an administrator!'; + $this->debug("download_small_document - cannot read $filename", $session_id); + return new SOAP_Value('return',"{urn:$this->namespace}kt_response", $response); + } + $content = fread($fp, filesize($filename)); + fclose($fp); + $content = base64_encode($content); $response['status_code'] = KTWS_SUCCESS; $response['message'] = $content; @@ -3743,9 +3775,9 @@ class KTWebService * @param int $document_id * @return kt_metadata_response */ - function get_document_metadata($session_id,$document_id) + function get_document_metadata($session_id, $document_id, $version = null) { - $this->debug("get_document_metadata('$session_id',$document_id)"); + $this->debug("get_document_metadata('$session_id',$document_id, $version)"); $kt = &$this->get_ktapi($session_id ); if (is_array($kt)) @@ -3755,7 +3787,12 @@ class KTWebService $response = KTWebService::_status(KTWS_ERR_INVALID_DOCUMENT); - $document = &$kt->get_document_by_id($document_id); + if(is_numeric($version)){ + $document = &$kt->get_document_by_metadata_version($document_id, $version); + }else { + $document = &$kt->get_document_by_id($document_id); + } + if (PEAR::isError($document)) { $response['message'] = $document->getMessage(); diff --git a/lib/documentmanagement/Document.inc b/lib/documentmanagement/Document.inc index 82abff1..13c2cba 100644 --- a/lib/documentmanagement/Document.inc +++ b/lib/documentmanagement/Document.inc @@ -5,7 +5,7 @@ * KnowledgeTree Community Edition * Document Management Made Simple * Copyright (C) 2008, 2009, 2010 KnowledgeTree Inc. - * + * * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 3 as published by the @@ -169,7 +169,7 @@ class Document { function getStoragePath() { return $this->_oDocumentContentVersion->getStoragePath(); } function setStoragePath($sNewValue) { $this->_oDocumentContentVersion->setStoragePath($sNewValue); } - + /** @@ -679,6 +679,50 @@ class Document { } // }}} + // {{{ getContentVersionIdFromVersion + function getContentVersionIdFromVersion($version) + { + $aVersion = explode('.', $version); + $major = $aVersion[0]; + $minor = $aVersion[1]; + + $doc_id = $this->iId; + + $query = "select id from document_content_version where document_id = $doc_id and major_version = $major and minor_version = $minor"; + + $result = DBUtil::getOneResultKey($query, 'id'); + + if(empty($result)){ + return PEAR::raiseError("Requested content version, $version, does not exist."); + } + + if(PEAR::isError($result)){ + return $result; + } + + return $result; + } + // }}} + + // {{{ getMetadataVersionIdFromVersion + static function getMetadataVersionIdFromVersion($doc_id, $version) + { + $query = "select id from document_metadata_version where document_id = $doc_id and metadata_version = $version"; + + $result = DBUtil::getOneResultKey($query, 'id'); + + if(empty($result)){ + return PEAR::raiseError("Requested metadata version, $version, does not exist."); + } + + if(PEAR::isError($result)){ + return $result; + } + + return $result; + } + // }}} + // {{{ delete function delete() { $this->_oDocumentCore->setMetadataVersionId(null); diff --git a/lib/documentmanagement/documentmetadataversion.inc.php b/lib/documentmanagement/documentmetadataversion.inc.php index 2f9c766..e1079f8 100644 --- a/lib/documentmanagement/documentmetadataversion.inc.php +++ b/lib/documentmanagement/documentmetadataversion.inc.php @@ -5,32 +5,32 @@ * KnowledgeTree Community Edition * Document Management Made Simple * Copyright (C) 2008, 2009, 2010 KnowledgeTree Inc. - * - * + * + * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 3 as published by the * Free Software Foundation. - * + * * 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 General Public License for more * details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, + * + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, * California 94120-7775, or email info@knowledgetree.com. - * + * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU General Public License version 3. - * + * * In accordance with Section 7(b) of the GNU General Public License version 3, * these Appropriate Legal Notices must retain the display of the "Powered by - * KnowledgeTree" logo and retain the original copyright notice. If the display of the + * KnowledgeTree" logo and retain the original copyright notice. If the display of the * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices - * must display the words "Powered by KnowledgeTree" and retain the original + * must display the words "Powered by KnowledgeTree" and retain the original * copyright notice. * Contributor( s): ______________________________________ * @@ -73,7 +73,7 @@ class KTDocumentMetadataVersion extends KTEntity { var $iWorkflowStateId; var $_aFieldToSelect; - + public static $_versionFields = null; // {{{ getters/setters @@ -101,11 +101,11 @@ class KTDocumentMetadataVersion extends KTEntity { function getWorkflowStateId() { return $this->iWorkflowStateId; } function setWorkflowStateId($mValue) { $this->iWorkflowStateId = $mValue; } // }}} - + function __construct() { $this->_aFieldToSelect = KTDocumentMetaDataVersion::getFieldsToSelect(); } - + function getFieldsToSelect() { if(self::$_versionFields == null) { $sTable = KTUtil::getTableName('document_metadata_version'); @@ -116,24 +116,24 @@ class KTDocumentMetadataVersion extends KTEntity { } self::$_versionFields = $result; } - return self::$_versionFields; + return self::$_versionFields; } - + function getFieldType($dbType) { /* Integer test */ if(strpos($dbType, "int") !== FALSE) { return "i"; } - + /* Time test */ if(strpos($dbType, "time") !== FALSE) { return "d"; } - + /* Default */ return "s"; } - + function &createFromArray($aOptions) { return KTEntityUtil::createFromArray('KTDocumentMetadataVersion', $aOptions); @@ -163,7 +163,7 @@ class KTDocumentMetadataVersion extends KTEntity { 'document_id' => $iDocumentId, ), array( 'multi' => true, - 'orderby' => 'version_created DESC', + 'orderby' => 'version_created DESC, metadata_version DESC', )); } diff --git a/lib/storage/ondiskhashedstoragemanager.inc.php b/lib/storage/ondiskhashedstoragemanager.inc.php index 8e1b8eb..e980853 100644 --- a/lib/storage/ondiskhashedstoragemanager.inc.php +++ b/lib/storage/ondiskhashedstoragemanager.inc.php @@ -8,7 +8,7 @@ * KnowledgeTree Community Edition * Document Management Made Simple * Copyright (C) 2008, 2009, 2010 KnowledgeTree Inc. - * + * * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 3 as published by the @@ -176,6 +176,20 @@ class KTOnDiskHashedStorageManager extends KTStorageManager { return sprintf("%s/%s", $oConfig->get('urls/documentRoot'), $this->getPath($oDocument)); } + function temporaryFileForVersion($iVersionId) { + $oConfig =& KTConfig::getSingleton(); + + // get path to the content version + $oContentVersion = KTDocumentContentVersion::get($iVersionId); + $sPath = sprintf("%s/%s", $oConfig->get('urls/documentRoot'), $this->getPath($oContentVersion)); + + // Ensure the file exists + if (file_exists($sPath)) { + return $sPath; + } + return false; + } + function freeTemporaryFile($sPath) { // Storage uses file-on-filesystem for temporaryFile return; diff --git a/sql/mysql/install/structure.sql b/sql/mysql/install/structure.sql index ff5db61..5883e56 100644 --- a/sql/mysql/install/structure.sql +++ b/sql/mysql/install/structure.sql @@ -633,8 +633,8 @@ CREATE TABLE `download_files` ( `session` varchar(100) NOT NULL, `download_date` timestamp NULL default CURRENT_TIMESTAMP, `downloaded` int(10) unsigned NOT NULL default '0', - `filesize` int(10) unsigned NOT NULL, - `content_version` int(10) unsigned NOT NULL, + `filesize` int(10) unsigned, + `content_version` int(10) unsigned, `hash` varchar(100) NOT NULL, PRIMARY KEY (`document_id`,`session`), CONSTRAINT `download_files_ibfk_1` FOREIGN KEY (`document_id`) REFERENCES `documents` (`id`) ON DELETE CASCADE ON UPDATE CASCADE diff --git a/sql/mysql/upgrade/3.7.0.4/download_files.sql b/sql/mysql/upgrade/3.7.0.4/download_files.sql new file mode 100644 index 0000000..ca50ef9 --- /dev/null +++ b/sql/mysql/upgrade/3.7.0.4/download_files.sql @@ -0,0 +1 @@ +ALTER TABLE download_files CHANGE COLUMN content_version content_version int(10) unsigned, CHANGE COLUMN filesize filesize int(10) unsigned; \ No newline at end of file diff --git a/tests/runtests.php b/tests/runtests.php index 6e99b4f..39ab51e 100644 --- a/tests/runtests.php +++ b/tests/runtests.php @@ -36,12 +36,12 @@ class UnitTests extends TestSuite { // if Electronic Signatures are NOT enabled for the API, new tests may not // include the check which allows the tests to be bypassed when esignatures // are not on, so if you have failures, check there first :) - $this->addFile('api/testElectronicSignatures.php'); +// $this->addFile('api/testElectronicSignatures.php'); // Web Service tests $this->addFile('webservices/testRest.php'); - $this->addFile('webservices/testSoap.php'); - + $this->addFile('webservices/testSoap.php'); + // $this->addFile('SQLFile/test_sqlfile.php'); // $this->addFile('cache/testCache.php'); // $this->addFile('config/testConfig.php'); diff --git a/tests/webservices/testSoap.php b/tests/webservices/testSoap.php index 855194a..6762d66 100644 --- a/tests/webservices/testSoap.php +++ b/tests/webservices/testSoap.php @@ -16,10 +16,14 @@ class SOAPTestCase extends KTUnitTestCase { * @var string $rootUrl The root server url for the rest web service */ var $rootUrl; - + var $uploads_dir; + public $client; private $user; private $pass; + private $content = 'New document for testing the soap webservice api'; + private $content_update = 'Updated document for testing the soap webservice api'; + private $reason = 'Running unit tests'; /** * This method sets up the server url @@ -31,6 +35,10 @@ class SOAPTestCase extends KTUnitTestCase { $this->rootUrl = $url.'/ktwebservice/webservice.php?'; $this->user = isset($_GET['user']) ? $_GET['user'] : 'admin'; $this->pass = isset($_GET['pass']) ? $_GET['pass'] : 'admin'; + + // Login and authenticate + $this->connect(); + $this->login('127.0.0.1'); } /** @@ -38,15 +46,17 @@ class SOAPTestCase extends KTUnitTestCase { */ public function tearDown() { + // Logout + $this->logout(); } - function connect() + private function connect() { $wsdl = $this->rootUrl . "wsdl"; $this->client = new SoapClient($wsdl); } - function login($ip = null) + private function login($ip = null) { $res = $this->client->__soapCall("login", array($this->user, $this->pass, $ip)); if($res->status_code != 0){ @@ -55,67 +65,210 @@ class SOAPTestCase extends KTUnitTestCase { $this->session = $res->message; } + private function logout() + { + $result = $this->client->__soapCall("logout", array($this->session)); + if($result->status_code != 0){ + return true; + } + } - function getDocTypes() + private function getDocTypes() { $result = $this->client->__soapCall("get_document_types", array($this->session)); return $result->document_types; } - function search($expr) + private function search($expr) { $result = $this->client->__soapCall("search", array($this->session, $expr, '')); return $result->hits; } - function getFolderDetail($folder, $parentId = 1) + private function getFolderDetail($folder, $parentId = 1) { $result = $this->client->__soapCall("get_folder_detail_by_name", array($this->session, $folder, $parentId)); return $result; } - function createFolder($parent_id, $folder) + private function createFolder($parent_id, $folder) { $result = $this->client->__soapCall("create_folder", array($this->session, $parent_id, $folder)); return $result; } - function deleteFolder($folder_id) + private function createFolderShortcut($target_folder_id, $source_folder_id) { - $result = $this->client->__soapCall("delete_folder", array($this->session, "$folder_id", 'Testing')); + $result = $this->client->__soapCall("create_folder_shortcut", array($this->session, $target_folder_id, $source_folder_id)); return $result; } - function logout() + private function deleteFolder($folder_id) { - $result = $this->client->__soapCall("logout", array($this->session)); - if($result->status_code != 0){ - return true; - } + $result = $this->client->__soapCall("delete_folder", array($this->session, $folder_id, 'Testing')); + return $result; + } + + private function getFolderShortcuts($folder_id) + { + $result = $this->client->__soapCall("get_folder_shortcuts", array($this->session, $folder_id)); + return $result; + } + + private function getDocumentVersionHistory($document_id) + { + $result = $this->client->__soapCall("get_document_version_history", array($this->session, $document_id)); + return $result; + } + + private function createDocument($folder_id, $title, $filename, $documenttype = 'Default') + { + global $default; + $uploads_dir = $default->uploadDirectory; + + // create document in uploads folder + $tempfilename = tempnam($uploads_dir, 'myfile'); + $fp = fopen($tempfilename, 'wt'); + fwrite($fp, $this->content); + fclose($fp); + + // call add document to upload into repo + $result = $this->client->__soapCall("add_document", array($this->session, $folder_id, $title, $filename, $documenttype, $tempfilename)); + return $result; + } + + private function createSmallDocument($folder_id, $title, $filename, $documenttype = 'Default') + { + global $default; + $uploads_dir = $default->uploadDirectory; + + // create document in uploads folder + $base64 = base64_encode($this->content); + + // call add document to upload into repo + $result = $this->client->__soapCall("add_small_document", array($this->session, $folder_id, $title, $filename, $documenttype, $base64)); + return $result; + } + + private function checkinDocument($document_id, $filename, $major_update = false) + { + global $default; + $uploads_dir = $default->uploadDirectory; + + // create document in uploads folder + $tempfilename = tempnam($uploads_dir, 'myfile'); + $fp = fopen($tempfilename, 'wt'); + fwrite($fp, $this->content_update); + fclose($fp); + + // call add document to upload into repo + $result = $this->client->__soapCall("checkin_document", array($this->session, $document_id, $filename, $this->reason, $tempfilename, $major_update)); + return $result; + } + + private function checkinSmallDocument($document_id, $filename, $major_update = false) + { + global $default; + $uploads_dir = $default->uploadDirectory; + + // encode as base64 + $base64 = base64_encode($this->content_update); + + // call add document to upload into repo + $result = $this->client->__soapCall("checkin_small_document", array($this->session, $document_id, $filename, $this->reason, $base64, $major_update)); + return $result; } - - // now the test functions - + + private function checkoutDocument($document_id, $download = true) + { + $result = $this->client->__soapCall("checkout_document", array($this->session, $document_id, $this->reason, $download)); + return $result; + } + + private function checkoutSmallDocument($document_id, $download = true) + { + $result = $this->client->__soapCall("checkout_small_document", array($this->session, $document_id, $this->reason, $download)); + return $result; + } + + private function createDocumentShortcut($folder_id, $target_document_id) + { + $result = $this->client->__soapCall("create_document_shortcut", array($this->session, $folder_id, $target_document_id)); + return $result; + } + + private function getDocumentShortcuts($document_id) + { + $result = $this->client->__soapCall("get_document_shortcuts", array($this->session, $document_id)); + return $result; + } + + private function getFolderContents($folder_id, $depth=1, $what='DFS') + { + $result = $this->client->__soapCall("get_folder_contents", array($this->session, $folder_id, $depth, $what)); + return $result; + } + + private function getDocumentMetadata($document_id, $version = null) + { + $result = $this->client->__soapCall("get_document_metadata", array($this->session, $document_id, $version)); + return $result; + } + + private function updateDocumentMetadata($document_id, $metadata, $sysdata=null) + { + $result = $this->client->__soapCall("update_document_metadata", array($this->session, $document_id, $metadata, $sysdata)); + return $result; + } + + private function downloadDocument($document_id, $version = null) + { + $result = $this->client->__soapCall("download_document", array($this->session, $document_id, $version)); + return $result; + } + + private function downloadSmallDocument($document_id, $version = null) + { + $result = $this->client->__soapCall("download_small_document", array($this->session, $document_id, $version)); + return $result; + } + + private function doDownload($url) + { + $ch = curl_init($url); + curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch,CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch,CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch,CURLOPT_RETURNTRANSFER, true); + + $download = curl_exec($ch); + $status = curl_getinfo($ch,CURLINFO_HTTP_CODE); + + $error = curl_errno($ch); + + curl_close($ch); + + return array('status' => $status, 'error' => $error, 'download' => $download); + } + + /* *** now the test functions *** */ + /** * Tests finding of a folder or folder detail by name * Runs the following sub-tests: * . Folder Detail by Name in root folder (no duplicate names) * . Folder Detail by Name in subfolder of root folder (no duplicate names) * . Folder Detail by Name in subfolder of root folder (duplicate names) - * + * * NOTE there are less tests here because we cannot test the get_folder_by_name function since it does not exist within the web service code */ public function testGetFolderByName() { - // Login and authenticate - $this->connect(); - $this->login('127.0.0.1'); - // set up $root_folder_id = array(); $sub_folder_id = array(); $folders[0][1] = 'Root Folder'; - + // Create a sub folder in the root folder $parentId = 1; $folderName = 'Test api sub-folder ONE'; @@ -124,7 +277,7 @@ class SOAPTestCase extends KTUnitTestCase { $folders[$parentId][$response->id] = $folderName; $this->assertEqual($response->status_code, 0); $this->assertFalse(!empty($response->message)); - + // Create a second sub folder in the root folder $parentId = 1; $folderName = 'Test api sub-folder TWO'; @@ -133,7 +286,7 @@ class SOAPTestCase extends KTUnitTestCase { $folders[$parentId][$response->id] = $folderName; $this->assertEqual($response->status_code, 0); $this->assertFalse(!empty($response->message)); - + // Create a sub folder in the first sub folder $parentId = $root_folder_id[0]; $folderName = 'Test api sub-folder THREE'; @@ -142,7 +295,7 @@ class SOAPTestCase extends KTUnitTestCase { $folders[$parentId][$response->id] = $folderName; $this->assertEqual($response->status_code, 0); $this->assertFalse(!empty($response->message)); - + // Create a sub folder within the first sub folder which shares a name with one of the root sub folders $parentId = $sub_folder_id[0][0]; $folderName = 'Test api sub-folder TWO'; @@ -151,7 +304,7 @@ class SOAPTestCase extends KTUnitTestCase { $folders[$parentId][$response->id] = $folderName; $this->assertEqual($response->status_code, 0); $this->assertFalse(!empty($response->message)); - + // Create a second sub folder in the first sub folder $parentId = $root_folder_id[0]; $folderName = 'Test api sub-folder FOUR'; @@ -169,7 +322,7 @@ class SOAPTestCase extends KTUnitTestCase { $folders[$parentId][$response->id] = $folderName; $this->assertEqual($response->status_code, 0); $this->assertFalse(!empty($response->message)); - + // Create a sub folder within the second sub folder which shares a name with a sub folder in the first sub folder $parentId = $sub_folder_id[1][0]; $folderName = 'Test api sub-folder THREE'; @@ -180,7 +333,7 @@ class SOAPTestCase extends KTUnitTestCase { $this->assertFalse(!empty($response->message)); // NOTE default parent is 1, so does not need to be declared when searching the root folder, but we use it elsewhere - + // Fetching of root folder $parentId = 0; $folderName = 'Root Folder'; @@ -190,7 +343,7 @@ class SOAPTestCase extends KTUnitTestCase { if (($response->status_code == 0)) { $this->assertEqual($folders[$parentId][$response->id], $folderName); } - + // Folder Detail by Name in root folder (no duplicate names) $parentId = 1; $folderName = 'Test api sub-folder ONE'; @@ -201,7 +354,7 @@ class SOAPTestCase extends KTUnitTestCase { if (($response->status_code == 0)) { $this->assertEqual($folders[$parentId][$response->id], $folderName); } - + // Folder Detail by Name in sub folder of root folder (no duplicate names) $parentId = $root_folder_id[0]; $folderName = 'Test api sub-folder FOUR'; @@ -211,7 +364,7 @@ class SOAPTestCase extends KTUnitTestCase { if (($response->status_code == 0)) { $this->assertEqual($folders[$parentId][$response->id], $folderName); } - + // Folder Detail by Name in root folder (duplicate names) $parentId = 1; $folderName = 'Test api sub-folder TWO'; @@ -221,7 +374,7 @@ class SOAPTestCase extends KTUnitTestCase { if (($response->status_code == 0)) { $this->assertEqual($folders[$parentId][$response->id], $folderName); } - + // Folder Detail by Name in sub folder of root folder (duplicate names) $parentId = $root_folder_id[0]; $folderName = 'Test api sub-folder THREE'; @@ -231,7 +384,7 @@ class SOAPTestCase extends KTUnitTestCase { if (($response->status_code == 0)) { $this->assertEqual($folders[$parentId][$response->id], $folderName); } - + // Negative test with non duplicated folder - look for folder in location it does not exist $parentId = $root_folder_id[0]; $folderName = 'Test api sub-folder ONE'; @@ -239,7 +392,7 @@ class SOAPTestCase extends KTUnitTestCase { $this->assertNotEqual($response->status_code, 0); $this->assertTrue(!empty($response->message)); $this->assertNotEqual($folders[$parentId][$response->id], $folderName); - + // Negative test with duplicated folder - look for folder with incorrect parent id, result should not match expected folder $parentId = 1; $actualParentId = $sub_folder_id[0][0]; @@ -251,15 +404,511 @@ class SOAPTestCase extends KTUnitTestCase { // but not the one we wanted $expectedResponse = $this->getFolderDetail($folderName, $actualParentId); $this->assertNotEqual($response->id, $expectedResponse->id); - + // Clean up - delete all of the folders foreach ($root_folder_id as $folder_id) { $this->deleteFolder($folder_id); } - - // Logout - $this->logout(); } + /** + * Tests the creation of folders and folder shortcuts, getting the folder shortcut(s) + * WebService V3 and higher + */ + public function testCreateFolderShortcut() + { + // if V3 + if(LATEST_WEBSERVICE_VERSION < 3){ + return ; + } + + // Create folder 1 + $result = $this->createFolder(1, 'Test Shortcut Container'); + $this->assertEqual($result->status_code, 0, 'Create folder - '.$result->message); + $parentFolderId = $result->id; + + // Create folder 2 + $result = $this->createFolder(1, 'Test Shortcut Target'); + $this->assertEqual($result->status_code, 0, 'Create folder - '.$result->message); + $targetFolderId = $result->id; + + // Create folder 3 + $result = $this->createFolder($targetFolderId, 'Test Shortcut Target 2'); + $this->assertEqual($result->status_code, 0, 'Create folder - '.$result->message); + $target2FolderId = $result->id; + + // Create shortcut in folder 1 targeting folder 2 + $result = $this->createFolderShortcut($parentFolderId, $targetFolderId); + $this->assertEqual($result->status_code, 0, 'Create folder Shortcut - '.$result->message); + + $shortcutId = $result->id; + $linkedFolderId = $result->linked_folder_id; + $this->assertTrue(is_numeric($shortcutId), 'Shortcut id should be numeric'); + $this->assertTrue(is_numeric($linkedFolderId), 'Linked folder id should be numeric'); + $this->assertEqual($linkedFolderId, $targetFolderId, 'Shortcut should contain link the target folder'); + + // Create shortcut in folder 1 targeting folder 3 + $result = $this->createFolderShortcut($parentFolderId, $target2FolderId); + $this->assertEqual($result->status_code, 0, 'Create folder shortcut - '.$result->message); + + $shortcut2Id = $result->id; + $linkedFolder2Id = $result->linked_folder_id; + $this->assertTrue(is_numeric($shortcut2Id), 'Shortcut id should be numeric'); + $this->assertTrue(is_numeric($linkedFolder2Id), 'Linked folder id should be numeric'); + $this->assertEqual($linkedFolder2Id, $target2FolderId, 'Shortcut should contain link the target folder'); + + // Get the folder shortcut details + $result = $this->getFolderShortcuts($targetFolderId); + $this->assertEqual($result->status_code, 0, 'Should return list of folder shortcuts - '.$result->message); + + $shortcuts = $result[1]; + foreach ($shortcuts as $item) { + $this->assertEqual($item->id, $shortcutId); + $this->assertEqual($item->linked_folder_id, $targetFolderId); + } + + $result = $this->getFolderShortcuts($target2FolderId); + $this->assertEqual($result->status_code, 0, 'Should return list of folder shortcuts - '.$result->message); + + $shortcuts2 = $result[1]; + foreach ($shortcuts2 as $item) { + $this->assertEqual($item->id, $shortcut2Id); + $this->assertEqual($item->linked_folder_id, $target2FolderId); + } + + // delete and cleanup + $this->deleteFolder($parentFolderId); + $this->deleteFolder($targetFolderId); + } + + /** + * Tests the document upload and the creation and retrieval of document shortcuts + * WS V3 + */ + public function testCreateDocumentShortcut() + { + // if V3 + if(LATEST_WEBSERVICE_VERSION < 3){ + //$this->assertEqual(LATEST_WEBSERVICE_VERSION, 3, 'Webservice version is less than 3. Exiting test, functionality is V3 only'); + return ; + } + + // Create folder 1 containing the shortcut + $result = $this->createFolder(1, 'Test Shortcut Container'); + $this->assertEqual($result->status_code, 0, 'Create folder - '.$result->message); + $parentFolderId = $result->id; + + // Create folder 2 containing the document + $result = $this->createFolder(1, 'Test Shortcut Target'); + $this->assertEqual($result->status_code, 0, 'Create folder - '.$result->message); + $targetFolderId = $result->id; + + // Upload document to folder 2 + $result = $this->createDocument($targetFolderId, 'Target Doc', 'target.txt'); + $this->assertEqual($result->status_code, 0, 'Create document - '.$result->message); + $documentId = $result->document_id; + $this->assertTrue(is_numeric($documentId), 'Document id should be numeric'); + + // Create shortcut in folder 1, pointing to the document in folder 2 + $result = $this->createDocumentShortcut($parentFolderId, $documentId); + $this->assertEqual($result->status_code, 0, 'Create document shortcut - '.$result->message); + $shortcutId = $result->document_id; + $linkedDocumentId = $result->linked_document_id; + $this->assertTrue(is_numeric($shortcutId), 'Shortcut id should be numeric'); + $this->assertTrue(is_numeric($linkedDocumentId), 'Linked document id should be numeric'); + $this->assertEqual($linkedDocumentId, $documentId, 'Shortcut should contain link to the target document'); + + // delete and cleanup + $this->deleteFolder($parentFolderId); + $this->deleteFolder($targetFolderId); + } + + /** + * Tests document uploads, checkin / checkout, downloads and document version downloads (V3) + * Normal documents and small / base64 documents + */ + public function testUploadDownloadDocument() + { + // Create folder containing the documents + $result = $this->createFolder(1, 'Test Container'); + $this->assertEqual($result->status_code, 0, 'Create folder - '.$result->message); + $folderId = $result->id; + + // Upload document to folder + $filename = 'test_doc.txt'; + $result = $this->createDocument($folderId, 'Test Doc', $filename); + $this->assertEqual($result->status_code, 0, 'Create document - '.$result->message); + $documentId = $result->document_id; + $this->assertTrue(is_numeric($documentId), 'Document id should be numeric'); + + // Get the download url for the document + $result = $this->downloadDocument($documentId); + $this->assertEqual($result->status_code, 0, 'Get document download url - '.$result->message); + $url = $result->message; + $this->assertTrue(is_string($url), 'URL should be a string'); + $this->assertTrue(strpos($url, 'http') !== false, 'URL should contain http'); + + // Download the document + $result = $this->doDownload($url); + $this->assertEqual($result['status'], 200, 'Status should be code 200 for success - '.$result['status']); + $this->assertEqual($result['error'], 0, 'Error code should be 0 for success - '.$result['error']); + $this->assertEqual($result['download'], $this->content, 'Document content should be the same as that uploaded'); + + // ---------- + + // Upload base64 document to folder + $filename2 = 'test_base64_doc.txt'; + $result = $this->createSmallDocument($folderId, 'Test Base64 Doc', $filename2); + $this->assertEqual($result->status_code, 0, 'Create base64 document - '.$result->message); + $documentId2 = $result->document_id; + $this->assertTrue(is_numeric($documentId2), 'Document id should be numeric'); + + // Download base64 document + $result = $this->downloadSmallDocument($documentId2); + $this->assertEqual($result->status_code, 0, 'Download small document - '.$result->message); + $content = $result->message; + $this->assertTrue(is_string($content), 'Content should be a string'); + $content = base64_decode($content); + $this->assertEqual($content, $this->content, 'Document content should be the same as that uploaded'); + + if(LATEST_WEBSERVICE_VERSION < 3){ + // delete and cleanup + $this->deleteFolder($folderId); + return ; + } + + /* *** V3 functions *** */ + + // Checkout first document + $result = $this->checkoutDocument($documentId); + $this->assertEqual($result->status_code, 0, 'Checkout document - '.$result->message); + $checkoutBy = $result->checked_out_by; + $checkoutDate = $result->checked_out_date; + $url = $result->message; + $this->assertFalse(is_null($checkoutDate), 'Checked out date should not be null / empty - '.$checkoutDate); + $this->assertEqual($checkoutBy, 'Administrator', 'Using the Administrative user, checked out user must match - '.$checkoutBy); + $this->assertTrue(is_string($url), 'Download URL should be a string'); + $this->assertTrue(strpos($url, 'http') !== false, 'Download URL should contain http'); + + // Download the document + $result = $this->doDownload($url); + $content = $result['download']; + $this->assertEqual($result['status'], 200, 'Status should be code 200 for success - '.$result['status']); + $this->assertEqual($result['error'], 0, 'Error code should be 0 for success - '.$result['error']); + $this->assertEqual($result['download'], $this->content, 'Document content should be the same as that uploaded'); + + // ---------- + + // Checkin a new version + $result = $this->checkinDocument($documentId, $filename); + $this->assertEqual($result->status_code, 0, 'Checkin document - '.$result->message); + $checkoutBy = $result->checked_out_by; + $this->assertTrue(empty($checkoutBy) || $checkoutBy == 'n/a', 'Document should no longer be checked out by anyone - '.$checkoutBy); + + // Download new version + $result = $this->downloadDocument($documentId); + $this->assertEqual($result->status_code, 0, 'Get checkedin document download url - '.$result->message); + $url = $result->message; + + // Download the document + $result = $this->doDownload($url); + $this->assertEqual($result['download'], $this->content_update, 'Document content should be the same as the updated content'); + + // ---------- + + // Get previous versions of the document + $result = $this->getDocumentVersionHistory($documentId); + $this->assertEqual($result->status_code, 0, 'Get document version history - '.$result->message); + $history = $result->history; + $this->assertTrue(is_array($history), 'Version history should be an array'); + $this->assertEqual(count($history), 2, 'Version history should contain 2 items / versions'); + + // Get the previous version number + $version = isset($history[1]) ? $history[1]->content_version : null; + + // Download previous version + $result = $this->downloadDocument($documentId, $version); + $this->assertEqual($result->status_code, 0, "Get document download url for previous version ($version) - ".$result->message); + $url = $result->message; + + // Download the document + $result = $this->doDownload($url); + $this->assertEqual($result['status'], 200, 'Status should be code 200 for success - '.$result['status']); + $this->assertEqual($result['error'], 0, 'Error code should be 0 for success - '.$result['error']); + $this->assertEqual($result['download'], $this->content, 'Document content should be the same as the original content of the initial upload'); + + // ---------- + + // Checkout base64 document + $result = $this->checkoutSmallDocument($documentId2); + $this->assertEqual($result->status_code, 0, 'Checkout base64 document - '.$result->message); + $checkoutBy = $result->checked_out_by; + $checkoutDate = $result->checked_out_date; + $content = $result->message; + $this->assertFalse(is_null($checkoutDate), 'Checked out date should not be null / empty - '.$checkoutDate); + $this->assertEqual($checkoutBy, 'Administrator', 'Using the Administrative user, checked out user must match - '.$checkoutBy); + $this->assertTrue(is_string($content), 'Base64 content should be a string'); + $content = base64_decode($content); + $this->assertEqual($content, $this->content, 'Document content should be the same as that uploaded'); + + // ---------- + + // Checkin a new base64 version + $result = $this->checkinSmallDocument($documentId2, $filename2); + $this->assertEqual($result->status_code, 0, 'Checkin base64 document - '.$result->message); + $checkoutBy = $result->checked_out_by; + $this->assertTrue(empty($checkoutBy) || $checkoutBy == 'n/a', 'Document should no longer be checked out by anyone - '.$checkoutBy); + + // Download new version + $result = $this->downloadSmallDocument($documentId2); + $this->assertEqual($result->status_code, 0, 'Download checkedin base64 document - '.$result->message); + $content = $result->message; + $this->assertTrue(is_string($content), 'Content should be a string'); + $content = base64_decode($content); + $this->assertEqual($content, $this->content_update, 'Document content should be the same as the updated content'); + + // ---------- + + // Get previous versions of the base64 document + $result = $this->getDocumentVersionHistory($documentId2); + $this->assertEqual($result->status_code, 0, 'Get document version history - '.$result->message); + $history = $result->history; + $this->assertTrue(is_array($history), 'Version history should be an array'); + $this->assertEqual(count($history), 2, 'Version history should contain 2 items / versions'); + + // Get the previous version number + $version = isset($history[1]) ? $history[1]->content_version : null; + + // Download previous version + $result = $this->downloadSmallDocument($documentId2, $version); + $this->assertEqual($result->status_code, 0, "Download previous version ($version) - ".$result->message); + $content = $result->message; + $this->assertTrue(is_string($content), 'Content should be a string'); + $content = base64_decode($content); + $this->assertEqual($content, $this->content, 'Document content should be the same as the original content of the initial upload'); + + // delete and cleanup + $this->deleteFolder($folderId); + } + + /** + * Tests getting and updating document metadata + */ + public function testDocumentMetadata() + { + // Create folder containing the documents + $result = $this->createFolder(1, 'Test Metadata Container'); + $this->assertEqual($result->status_code, 0, 'Create folder - '.$result->message); + $folderId = $result->id; + + // Upload document to folder + $filename = 'test_doc.txt'; + $result = $this->createDocument($folderId, 'Test Doc', $filename); + $this->assertEqual($result->status_code, 0, 'Create document - '.$result->message); + $documentId = $result->document_id; + $this->assertTrue(is_numeric($documentId), 'Document id should be numeric'); + + // get document metadata + $result = $this->getDocumentMetadata($documentId); + $this->assertEqual($result->status_code, 0, 'Get document metadata - '.$result->message); + $metadata = $result->metadata; + $this->assertTrue(is_array($metadata), 'Returned document metadata should be an array of fieldsets'); + + // Add a new tag and a document author + foreach ($metadata as $fieldset){ + $fields = $fieldset->fields; + switch($fieldset->fieldset){ + case 'Tag Cloud': + $field_name = 'Tag'; + $curr_val = 'n/a'; + $new_val = 'unit test'; + break; + case 'General information': + $field_name = 'Document Author'; + $curr_val = 'n/a'; + $new_val = 'Test Framework'; + break; + } + + foreach ($fields as $field){ + if($field->name == $field_name){ + $this->assertEqual($field->value, $curr_val, "The current value of the given field, $field_name, should be \"$curr_val\""); + // update the value + $field->value = $new_val; + } + if($field->value == 'n/a'){ + $field->value = ''; + } + } + } + + // update metadata + $result = $this->updateDocumentMetadata($documentId, $metadata); + + // get metadata - ensure it matches the updated metadata + $result = $this->getDocumentMetadata($documentId); + $this->assertEqual($result->status_code, 0, 'Get document metadata - '.$result->message); + $metadata = $result->metadata; + $this->assertTrue(is_array($metadata), 'Returned document metadata should be an array of fieldsets'); + + // Add a new tag and a document author + foreach ($metadata as $fieldset){ + $fields = $fieldset->fields; + switch($fieldset->fieldset){ + case 'Tag Cloud': + $field_name = 'Tag'; + $curr_val = 'unit test'; + break; + case 'General information': + $field_name = 'Document Author'; + $curr_val = 'Test Framework'; + break; + } + + foreach ($fields as $field){ + if($field->name == $field_name){ + $this->assertEqual($field->value, $curr_val, "The current value of the given field, $field_name, should be the same as the updated value: \"$curr_val\""); + } + } + } + + // Get previous versions of the document + $result = $this->getDocumentVersionHistory($documentId); + $this->assertEqual($result->status_code, 0, 'Get document version history - '.$result->message); + $history = $result->history; + $this->assertTrue(is_array($history), 'Version history should be an array'); + $this->assertEqual(count($history), 2, 'Version history should contain 2 items / versions'); + + // Get the previous version number + $version = isset($history[1]) ? $history[1]->metadata_version : null; + + // get document metadata for previous version + $result = $this->getDocumentMetadata($documentId, $version); + $this->assertEqual($result->status_code, 0, 'Get document metadata - '.$result->message); + $metadata = $result->metadata; + $this->assertTrue(is_array($metadata), 'Returned document metadata should be an array of fieldsets'); + + // Add a new tag and a document author + foreach ($metadata as $fieldset){ + $fields = $fieldset->fields; + switch($fieldset->fieldset){ + case 'Tag Cloud': + $field_name = 'Tag'; + $curr_val = 'n/a'; + break; + case 'General information': + $field_name = 'Document Author'; + $curr_val = 'n/a'; + break; + } + + foreach ($fields as $field){ + if($field->name == $field_name){ + $this->assertEqual($field->value, $curr_val, "The current value of the given field, $field_name, should be the same as the previous version's value: \"$curr_val\""); + } + } + } + + // delete and cleanup + $this->deleteFolder($folderId); + } + + /** + * Test getting the contents of a folder + * + */ + public function testGetFolderListing() + { + // create folder + $main_folder = 'Test Listing Container'; + $result = $this->createFolder(1, $main_folder); + $this->assertEqual($result->status_code, 0, 'Create folder - '.$result->message); + $folderId = $result->id; + + // create subfolder 1 + $sub_folder_name = 'Subfolder One'; + $result = $this->createFolder($folderId, $sub_folder_name); + $this->assertEqual($result->status_code, 0, 'Create subfolder 1 - '.$result->message); + $subFolderId1 = $result->id; + + // create subfolder 2 + $result = $this->createFolder($folderId, 'Subfolder Two'); + $this->assertEqual($result->status_code, 0, 'Create subfolder 2 - '.$result->message); + $subFolderId2 = $result->id; + + // create subfolder 3 under subfolder 1 + $result = $this->createFolder($subFolderId1, 'Subfolder Three'); + $this->assertEqual($result->status_code, 0, 'Create subfolder 3 under subfolder 1 - '.$result->message); + $subFolderId3 = $result->id; + + // upload document into main folder + $filename = 'test_doc.txt'; + $result = $this->createDocument($folderId, 'Test Doc', $filename); + $this->assertEqual($result->status_code, 0, 'Create document 1 in folder - '.$result->message); + $documentId = $result->document_id; + $this->assertTrue(is_numeric($documentId), 'Document id should be numeric'); + + // upload document 2 into main folder + $filename2 = 'test_doc2.txt'; + $result = $this->createDocument($folderId, 'Test Doc 2', $filename2); + $this->assertEqual($result->status_code, 0, 'Create document 1 in folder - '.$result->message); + $documentId2 = $result->document_id; + $this->assertTrue(is_numeric($documentId2), 'Document id should be numeric'); + + // upload document 3 into subfolder 1 + $filename3 = 'test_doc3.txt'; + $result = $this->createDocument($subFolderId1, 'Test Doc 3', $filename3); + $this->assertEqual($result->status_code, 0, 'Create document 1 in sub folder 1 - '.$result->message); + $documentId3 = $result->document_id; + $this->assertTrue(is_numeric($documentId3), 'Document id should be numeric'); + + // Get folder listing for folder 1 - folders only, depth of 1 + $result = $this->getFolderContents($folderId, 1, 'F'); + $this->assertEqual($result->status_code, 0, 'Get subfolders in folder - '.$result->message); + $folder_name = $result->folder_name; + $sub_folders = $result->items; + $this->assertEqual($folder_name, $main_folder, 'Folder name is - '.$folder_name); + $this->assertTrue(is_array($sub_folders), 'There should be an array of subfolders'); + $this->assertEqual(count($sub_folders), 2, 'There should be 2 subfolders'); + + // Get folder listing for folder 1 - folders and documents, infinite depth + $result = $this->getFolderContents($folderId, 5, 'FD'); + $this->assertEqual($result->status_code, 0, 'Get all subfolders and documents under the folder - '.$result->message); + $items = $result->items; + $this->assertTrue(is_array($items), 'There should be an array of subfolders and documents'); + $this->assertEqual(count($items), 4, 'There should be 2 subfolders and 2 documents in the immediate folder'); + + // Loop through items, find sub folder 1 + $docs = 0; + $folders = 0; + foreach ($items as $item){ + // increment count of item type + $folders = ($item->item_type == 'F') ? $folders + 1 : $folders; + $docs = ($item->item_type == 'D') ? $docs + 1 : $docs; + + if($item->id == $subFolderId1){ + $sub_items = $item->items; + + $this->assertTrue(is_array($sub_items), 'Subfolder 1 should contain an array of contents'); + $this->assertEqual(count($sub_items), 2, 'Subfolder 1 should contain a folder and document'); + + } + } + + $this->assertEqual($folders, 2, 'There should be 2 folders'); + $this->assertEqual($docs, 2, 'There should be 2 documents'); + + // Get folder listing for subfolder 1 - documents only, depth of 1 + $result = $this->getFolderContents($subFolderId1, 1, 'D'); + $this->assertEqual($result->status_code, 0, 'Get documents under subfolder 1 - '.$result->message); + $folder_name = $result->folder_name; + $items = $result->items; + $this->assertEqual($folder_name, $sub_folder_name, 'Subfolder name is - '.$folder_name); + $this->assertTrue(is_array($items), 'There should be an array of documents'); + $this->assertEqual(count($items), 1, 'There should be 1 document'); + + // delete and cleanup + $this->deleteFolder($folderId); + } } ?> \ No newline at end of file -- libgit2 0.21.4