diff --git a/ktapi/KTAPIBulkActions.inc.php b/ktapi/KTAPIBulkActions.inc.php new file mode 100644 index 0000000..e6b98bf --- /dev/null +++ b/ktapi/KTAPIBulkActions.inc.php @@ -0,0 +1,575 @@ +. + * + * 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 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices + * must display the words "Powered by KnowledgeTree" and retain the original + * copyright notice. + * + * @copyright 2008-2009, KnowledgeTree Inc. + * @license GNU General Public License version 3 + * @author KnowledgeTree Team + * @package KnowledgeTree API + * @version Version 0.9 + */ + +/** + * API for the handling bulk actions on documents and folders within KnowledgeTree + * + * @author KnowledgeTree Team + * @package KnowledgeTree API + * @version 0.9 + */ +class KTAPI_BulkActions +{ + /** + * Instance of the KTAPI object + * + * @access private + */ + private $ktapi; + + /** + * Constructs the bulk actions object + * + * @author KnowledgeTree Team + * @access public + * @param KTAPI $ktapi Instance of the KTAPI object + */ + function __construct(&$ktapi) + { + $this->ktapi = $ktapi; + } + + /** + * Bulk copies a list of folders and/or documents into the target folder. + * If any documents or folders fail to copy, an array is returned containing the document/folder object and the failure message. + * + * + * $ktapi = new KTAPI(); + * $session = $ktapi->start_system_session(); + * $document = $ktapi->get_document_by_id($documentid); + * + * $root = $ktapi->get_root_folder(); + * $newFolder = $root->add_folder("New target folder"); + * if(PEAR::isError($newFolder)) return; + * + * $aItems = array($document); + * $bulk = new KTAPI_BulkActions($ktapi); + * $res = $bulk->copy($aItems, $newFolder, 'Bulk copy'); + * + * // if documents / folders failed + * if(!empty($res)) { + * // display reason for documents failure + * foreach($res['docs'] as $failedDoc){ + * echo '
' . $failedDoc['object']->get_title() . ' - reason: '.$failedDoc['reason']; + * } + * // display reason for folders failure + * foreach($res['folders'] as $failedDoc){ + * echo '
' . $failedFolder['object']->get_folder_name() . ' - reason: '.$failedFolder['reason']; + * } + * } + *
+ * + * @author KnowledgeTree Team + * @access public + * @param array $items The folders and/or documents + * @param KTAPI_Folder $target_folder The target folder object + * @param string $reason The reason for performing the copy + * @return array|PEAR_Error Returns an array of documents and folders that couldn't be copied | PEAR_Error on failure + */ + function copy($items, &$target_folder, $reason) + { + if(empty($items)) return; + assert(!is_null($target_folder)); + assert($target_folder instanceof KTAPI_FOLDER); + + if(!is_array($items)){ + $items = array($items); + } + + // Check user has write permission on target folder + $result = $this->ktapi->can_user_access_object_requiring_permission($target_folder->get_folder(), KTAPI_PERMISSION_WRITE); + + if (PEAR::isError($result)) + { + return $result; + } + + // Copy the document or folder + // Items that fail are returned in an array with the reason for failure. + + $failed = array(); + foreach ($items as $item){ + assert($item instanceof KTAPI_Document || $item instanceof KTAPI_Folder); + + $docOrFolder = ($item instanceof KTAPI_Document) ? 'docs' : 'folders'; + + $res = $item->copy($target_folder, $reason); + + if(PEAR::isError($res)){ + $failed[$docOrFolder][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + } + + return $failed; + } + + /** + * Bulk moves a list of folders and/or documents into the target folder + * + * + * $ktapi = new KTAPI(); + * $session = $ktapi->start_system_session(); + * $document = $ktapi->get_document_by_id($documentid); + * + * $root = $ktapi->get_root_folder(); + * $newFolder = $root->add_folder("New target folder"); + * if(PEAR::isError($newFolder)) return; + * + * $aItems = array($document); + * $bulk = new KTAPI_BulkActions($ktapi) + * $res = $bulk->move($aItems, $newFolder, 'Bulk move'); + * + * // if documents / folders failed + * if(!empty($res)) { + * // display reason for documents failure + * foreach($res['docs'] as $failedDoc){ + * echo '
' . $failedDoc['object']->get_title() . ' - reason: '.$failedDoc['reason']; + * } + * // display reason for folders failure + * foreach($res['folders'] as $failedDoc){ + * echo '
' . $failedFolder['object']->get_folder_name() . ' - reason: '.$failedFolder['reason']; + * } + * } + *
+ * + * @author KnowledgeTree Team + * @access public + * @param array $items The folders and/or documents + * @param KTAPI_Folder $target_folder The target folder object + * @param string $reason The reason for performing the move + * @return void|PEAR_Error Nothing on success | PEAR_Error on failure + */ + function move($items, &$target_folder, $reason) + { + if(empty($items)) return; + assert(!is_null($target_folder)); + assert($target_folder instanceof KTAPI_FOLDER); + + if(!is_array($items)){ + $items = array($items); + } + + // Check user has write permission on target folder + $result = $this->ktapi->can_user_access_object_requiring_permission($target_folder->get_folder(), KTAPI_PERMISSION_WRITE); + + if (PEAR::isError($result)) + { + return $result; + } + + // Move the document or folder + // Items that fail are returned in an array with the reason for failure. + + $failed = array(); + foreach ($items as $item){ + assert($item instanceof KTAPI_Document || $item instanceof KTAPI_Folder); + + $docOrFolder = ($item instanceof KTAPI_Document) ? 'docs' : 'folders'; + + $res = $item->move($target_folder, $reason); + + if(PEAR::isError($res)){ + $failed[$docOrFolder][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + } + + return $failed; + } + + /** + * Performs a bulk checkout on a list of folders and/or documents + * + * + * $ktapi = new KTAPI(); + * $session = $ktapi->start_system_session(); + * $document = $ktapi->get_document_by_id($documentid); + * $folder = $ktapi->get_folder_by_name('New test folder'); + * + * $aItems = array($document, $folder); + * $bulk = new KTAPI_BulkActions($ktapi) + * $res = $bulk->checkout($aItems, 'Bulk archive'); + * + * // if documents / folders failed + * if(!empty($res)) { + * // display reason for documents failure + * foreach($res['docs'] as $failedDoc){ + * echo '
' . $failedDoc['object']->get_title() . ' - reason: '.$failedDoc['reason']; + * } + * // display reason for folders failure + * foreach($res['folders'] as $failedDoc){ + * echo '
' . $failedFolder['object']->get_folder_name() . ' - reason: '.$failedFolder['reason']; + * } + * } + *
+ * + * @author KnowledgeTree Team + * @access public + * @param array $items The folders and/or documents + * @param string $reason The reason for performing the checkout + * @return void|PEAR_Error Nothing with download set to false | PEAR_Error on failure + */ + function checkout($items, $reason) + { + if(empty($items)) return; + + if(!is_array($items)){ + $items = array($items); + } + + // Checkout the document or folder + // Items that fail are returned in an array with the reason for failure. + + $failed = array(); + foreach ($items as $item){ + // Documents + if($item instanceof KTAPI_Document){ + $res = $item->checkout($reason); + + if(PEAR::isError($res)){ + $failed['docs'][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + }else if($item instanceof KTAPI_Folder){ + // Folders - need to recurse in + DBUtil::startTransaction(); + $res = $this->recurseFolder($item, $reason, 'checkout'); + + if(PEAR::isError($res)){ + DBUtil::rollback(); + $failed['folders'][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + DBUtil::commit(); + } + } + + return $failed; + } + + /** + * Performs a bulk cancel checkout on a list of folders and/or documents + * + * @author KnowledgeTree Team + * @access public + * @param array $items The folders and/or documents + * @param string $reason The reason for cancelling the checkout + * @return void|PEAR_Error Nothing with download set to false | PEAR_Error on failure + */ + function undo_checkout($items, $reason) + { + if(empty($items)) return; + + if(!is_array($items)){ + $items = array($items); + } + + // Cancel checkout on the document or folder contents + // Items that fail are returned in an array with the reason for failure. + + $failed = array(); + foreach ($items as $item){ + // Documents + if($item instanceof KTAPI_Document){ + $res = $item->undo_checkout($reason); + + if(PEAR::isError($res)){ + $failed['docs'][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + }else if($item instanceof KTAPI_Folder){ + // Folders - need to recurse in + DBUtil::startTransaction(); + $res = $this->recurseFolder($item, $reason, 'undo_checkout'); + + if(PEAR::isError($res)){ + DBUtil::rollback(); + $failed['folders'][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + DBUtil::commit(); + } + } + + return $failed; + } + + /** + * Bulk immutes a list of documents + * + * @author KnowledgeTree Team + * @access public + * @param array $items The folders and/or documents + * @return void|PEAR_Error Nothing on success | PEAR_Error on failure + */ + function immute($items) + { + if(empty($items)) return; + + if(!is_array($items)){ + $items = array($items); + } + + // Immute the documents + // Items that fail are returned in an array with the reason for failure. + + $failed = array(); + foreach ($items as $item){ + // Documents + if($item instanceof KTAPI_Document){ + $res = $item->immute(); + + if(PEAR::isError($res)){ + $failed['docs'][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + }else if($item instanceof KTAPI_Folder){ + // Folders - need to recurse in + DBUtil::startTransaction(); + $res = $this->recurseFolder($item, null, 'immute'); + + if(PEAR::isError($res)){ + DBUtil::rollback(); + $failed['folders'][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + DBUtil::commit(); + } + } + + return $failed; + } + + /** + * Bulk deletes a list of folders and/or documents + * + * + * $ktapi = new KTAPI(); + * $session = $ktapi->start_system_session(); + * $document = $ktapi->get_document_by_id($documentid); + * $folder = $ktapi->get_folder_by_name('New test folder'); + * + * $aItems = array($document, $folder); + * $bulk = new KTAPI_BulkActions($ktapi) + * $res = $bulk->delete($aItems, 'Bulk delete'); + * + * // if documents / folders failed + * if(!empty($res)) { + * // display reason for documents failure + * foreach($res['docs'] as $failedDoc){ + * echo '
' . $failedDoc['object']->get_title() . ' - reason: '.$failedDoc['reason']; + * } + * // display reason for folders failure + * foreach($res['folders'] as $failedDoc){ + * echo '
' . $failedFolder['object']->get_folder_name() . ' - reason: '.$failedFolder['reason']; + * } + * } + *
+ * + * @author KnowledgeTree Team + * @access public + * @param array $items The folders and/or documents + * @param string $reason The reason for performing the deletion + * @return void|PEAR_Error Nothing on success | PEAR_Error on failure + */ + function delete($items, $reason) + { + if(empty($items)) return; + + if(!is_array($items)){ + $items = array($items); + } + + // Delete the document or folder + // Items that fail are returned in an array with the reason for failure. + + $failed = array(); + foreach ($items as $item){ + assert($item instanceof KTAPI_Document || $item instanceof KTAPI_Folder); + + $docOrFolder = ($item instanceof KTAPI_Document) ? 'docs' : 'folders'; + + $res = $item->delete($reason); + + if(PEAR::isError($res)){ + $failed[$docOrFolder][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + } + + return $failed; + } + + /** + * Bulk archives a list of folders and/or documents + * + * + * $ktapi = new KTAPI(); + * $session = $ktapi->start_system_session(); + * $document = $ktapi->get_document_by_id($documentid); + * $folder = $ktapi->get_folder_by_name('New test folder'); + * + * $aItems = array($document, $folder); + * $bulk = new KTAPI_BulkActions($ktapi) + * $res = $bulk->archive($aItems, 'Bulk archive'); + * + * // if documents / folders failed + * if(!empty($res)) { + * // display reason for documents failure + * foreach($res['docs'] as $failedDoc){ + * echo '
' . $failedDoc['object']->get_title() . ' - reason: '.$failedDoc['reason']; + * } + * // display reason for folders failure + * foreach($res['folders'] as $failedDoc){ + * echo '
' . $failedFolder['object']->get_folder_name() . ' - reason: '.$failedFolder['reason']; + * } + * } + *
+ * + * @author KnowledgeTree Team + * @access public + * @param array $items The folders and/or documents + * @param string $reason The reason for performing the archival + * @return void|PEAR_Error Nothing on success | PEAR_Error on failure + */ + function archive($items, $reason) + { + if(empty($items)) return; + + if(!is_array($items)){ + $items = array($items); + } + + // Archive the document or folder + // Items that fail are returned in an array with the reason for failure. + + $failed = array(); + foreach ($items as $item){ + // Documents + if($item instanceof KTAPI_Document){ + $res = $item->archive($reason); + + if(PEAR::isError($res)){ + $failed['docs'][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + }else if($item instanceof KTAPI_Folder){ + // Folders - need to recurse in + DBUtil::startTransaction(); + $res = $this->recurseFolder($item, $reason, 'archive'); + + if(PEAR::isError($res)){ + DBUtil::rollback(); + $failed['folders'][] = array('object' => $item, 'reason' => $res->getMessage()); + continue; + } + DBUtil::commit(); + } + } + + return $failed; + } + + /** + * Recursive function to perform a given action on a folder and contained documents. + * + * @author KnowledgeTree Team + * @access private + * @param KTAPI_Folder $folder The instance of the folder object being archived + * @param string $reason The reason for archiving + * @param string $action The action to be performed on the documents + * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure + */ + private function recurseFolder($folder, $reason = '', $action = 'archive') + { + if(!$folder instanceof KTAPI_Folder){ + return PEAR::raiseError('Object is not an instance of KTAPI_Folder'); + } + + // Archive contained documents + $listDocs = $folder->get_listing(1, 'D'); + if(!empty($listDocs)) { + + foreach ($listDocs as $docInfo){ + $doc = $this->ktapi->get_document_by_id($docInfo['id']); + + switch ($action){ + case 'archive': + $res = $doc->archive($reason); + break; + + case 'checkout': + $res = $doc->checkout($reason); + break; + + case 'undo_checkout': + $res = $doc->undo_checkout($reason); + break; + + case 'immute': + $res = $doc->immute(); + break; + } + + + if(PEAR::isError($res)){ + return $res; + } + } + } + + // Archive contained folders + $listFolders = $folder->get_listing(1, 'F'); + if(!empty($listFolders)) { + foreach ($listFolders as $folderItem){ + $res = $this->archiveFolder($folderItem, $reason); + + if(PEAR::isError($res)){ + return $res; + } + } + } + return; + } +} +?> \ No newline at end of file diff --git a/ktapi/KTAPIDocument.inc.php b/ktapi/KTAPIDocument.inc.php index 9bff361..21a84a6 100644 --- a/ktapi/KTAPIDocument.inc.php +++ b/ktapi/KTAPIDocument.inc.php @@ -711,6 +711,7 @@ class KTAPI_Document extends KTAPI_FolderItem DBUtil::commit(); + /* // FIXME do we need to refactor all trigger usage into the util function? $oKTTriggerRegistry = KTTriggerRegistry::getSingleton(); $aTriggers = $oKTTriggerRegistry->getTriggers('copyDocument', 'postValidate'); @@ -725,6 +726,7 @@ class KTAPI_Document extends KTAPI_FolderItem $oTrigger->setInfo($aInfo); $ret = $oTrigger->postValidate(); } + */ return KTAPI_Document::get($this->ktapi, $new_document->getId()); } @@ -1021,6 +1023,16 @@ class KTAPI_Document extends KTAPI_FolderItem return $user; } + DBUtil::startTransaction(); + $res = KTDocumentUtil::archive($this->document, $reason); + + if(PEAR::isError($res)){ + DBUtil::rollback(); + return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res); + } + DBUtil::commit(); + + /* list($permission, $user) = $perm_and_user; DBUtil::startTransaction(); @@ -1048,6 +1060,7 @@ class KTAPI_Document extends KTAPI_FolderItem $oTrigger->setInfo($aInfo); $ret = $oTrigger->postValidate(); } + */ } /** @@ -2321,6 +2334,9 @@ class KTAPI_Document extends KTAPI_FolderItem */ public function immute() { + if($this->is_checked_out()){ + return new PEAR_Error('Document is checked out and can\'t be set to immutable.'); + } $this->document->setImmutable(true); $this->document->update(); } diff --git a/ktapi/ktapi.inc.php b/ktapi/ktapi.inc.php index 3505cc2..22a4af8 100644 --- a/ktapi/ktapi.inc.php +++ b/ktapi/ktapi.inc.php @@ -58,6 +58,7 @@ require_once(KTAPI_DIR .'/KTAPIFolder.inc.php'); require_once(KTAPI_DIR .'/KTAPIDocument.inc.php'); require_once(KTAPI_DIR .'/KTAPIAcl.inc.php'); require_once(KTAPI_DIR .'/KTAPICollection.inc.php'); +require_once(KTAPI_DIR .'/KTAPIBulkActions.inc.php'); /** * This class defines functions that MUST exist in the inheriting class diff --git a/lib/documentmanagement/documentutil.inc.php b/lib/documentmanagement/documentutil.inc.php index 00461fe..2556283 100644 --- a/lib/documentmanagement/documentutil.inc.php +++ b/lib/documentmanagement/documentutil.inc.php @@ -152,6 +152,15 @@ class KTDocumentUtil { return PEAR::raiseError(_kt('Already checked out.')); } + if($oDocument->getImmutable()){ + return PEAR::raiseError(_kt('Document cannot be checked out as it is immutable')); + } + + // Check if the action is restricted by workflow on the document + if(!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.checkout')){ + return PEAR::raiseError(_kt('Checkout is restricted by the workflow state.')); + } + // FIXME at the moment errors this _does not_ rollback. $oDocument->setIsCheckedOut(true); @@ -186,12 +195,8 @@ class KTDocumentUtil { function archive($oDocument, $sReason) { - $this->startTransaction(); - $oDocument->setStatusID(ARCHIVED); - $res = $oDocument->update(); - - if (PEAR::isError($res) || ($res === false)) { - return PEAR::raiseError(_kt('There was a database error while trying to archive this file')); + if($oDocument->isSymbolicLink()){ + return PEAR::raiseError(_kt("It is not possible to archive a shortcut. Please archive the target document.")); } // Ensure the action is not blocked @@ -199,6 +204,13 @@ class KTDocumentUtil { return PEAR::raiseError(_kt('Document cannot be archived as it is restricted by the workflow.')); } + $oDocument->setStatusID(ARCHIVED); + $res = $oDocument->update(); + + if (PEAR::isError($res) || ($res === false)) { + return PEAR::raiseError(_kt('There was a database error while trying to archive this file')); + } + //delete all shortcuts linking to this document $aSymlinks = $oDocument->getSymbolicLinks(); foreach($aSymlinks as $aSymlink){ @@ -220,8 +232,6 @@ class KTDocumentUtil { $oDocumentTransaction = & new DocumentTransaction($oDocument, sprintf(_kt('Document archived: %s'), $sReason), 'ktcore.transactions.update'); $oDocumentTransaction->create(); - $this->commitTransaction(); - $oKTTriggerRegistry = KTTriggerRegistry::getSingleton(); $aTriggers = $oKTTriggerRegistry->getTriggers('archive', 'postValidate'); foreach ($aTriggers as $aTrigger) { @@ -1213,11 +1223,11 @@ $sourceDocument->getName(), } function rename($oDocument, $sNewFilename, $oUser) { - $oStorage =& KTStorageManagerUtil::getSingleton(); - + $oStorage =& KTStorageManagerUtil::getSingleton(); + $oKTConfig = KTConfig::getSingleton(); - $updateVersion = $oKTConfig->get('tweaks/incrementVersionOnRename', true); - + $updateVersion = $oKTConfig->get('tweaks/incrementVersionOnRename', true); + $iPreviousMetadataVersion = $oDocument->getMetadataVersionId(); $oOldContentVersion = $oDocument->_oDocumentContentVersion; @@ -1231,22 +1241,22 @@ $sourceDocument->getName(), KTDocumentUtil::copyMetadata($oDocument, $iPreviousMetadataVersion); } - + $res = $oStorage->renameDocument($oDocument, $oOldContentVersion, $sNewFilename); if (!$res) { return PEAR::raiseError(_kt('An error occurred while storing the new file')); } - - + + $oDocument->setLastModifiedDate(getCurrentDateTime()); $oDocument->setModifiedUserId($oUser->getId()); - + if($updateVersion) { // Update version number $oDocument->setMinorVersionNumber($oDocument->getMinorVersionNumber()+1); } - + $oDocument->_oDocumentContentVersion->setFilename($sNewFilename); $sType = KTMime::getMimeTypeFromFile($sNewFilename); diff --git a/tests/api/testBulkActions.php b/tests/api/testBulkActions.php new file mode 100644 index 0000000..3eb7297 --- /dev/null +++ b/tests/api/testBulkActions.php @@ -0,0 +1,368 @@ +ktapi = new KTAPI(); + $this->session = $this->ktapi->start_system_session(); + $this->root = $this->ktapi->get_root_folder(); + $this->bulk = new KTAPI_BulkActions($this->ktapi); + } + + /** + * End the ktapi session + */ + function tearDown() { + $this->session->logout(); + } + + /** + * Test the bulk copy functionality + */ + function testCopy() + { + // Create documents + $doc1 = $this->createDocument('Test Doc One', 'testdoc1.txt'); + $doc2 = $this->createDocument('Test Doc Two', 'testdoc2.txt'); + $doc3 = $this->createDocument('Test Doc Three', 'testdoc3.txt'); + $folder1 = $this->root->add_folder("New copy folder"); + $this->assertNotError($newFolder); + if(PEAR::isError($newFolder)) return; + + $doc4 = $this->createDocument('Test Doc Four', 'testdoc4.txt', $folder1); + + // Add a folder + $targetFolder = $this->root->add_folder("New target folder"); + $this->assertNotError($newFolder); + if(PEAR::isError($newFolder)) return; + + $aItems = array($doc1, $doc2, $doc3, $folder1); + + // Copy documents and folder into target folder + $res = $this->bulk->copy($aItems, $targetFolder, 'Testing bulk copy'); + + $this->assertTrue(empty($res)); + + // Check the documents copied + $listDocs = $targetFolder->get_listing(1, 'D'); + $this->assertTrue(count($listDocs) == 3); + + // Check the folder copied + $listFolders = $targetFolder->get_listing(1, 'F'); + $this->assertTrue(count($listFolders) == 1); + + // Check the document contained in the folder copied + $newFolderId = $listFolders[0]['id']; + $newFolder = $this->ktapi->get_folder_by_id($newFolderId); + $listSubDocs = $newFolder->get_listing(1, 'D'); + $this->assertTrue(count($listSubDocs) == 1); + + // Delete and expunge documents and folder + $this->deleteDocument($doc1); + $this->deleteDocument($doc2); + $this->deleteDocument($doc3); + $this->deleteDocument($doc4); + $targetFolder->delete('Testing bulk copy'); + $folder1->delete('Testing bulk copy'); + } + + /** + * Test the bulk move functionality + */ + function testMove() + { + // Create documents + $doc1 = $this->createDocument('Test Doc One', 'testdoc1.txt'); + $doc2 = $this->createDocument('Test Doc Two', 'testdoc2.txt'); + $doc3 = $this->createDocument('Test Doc Three', 'testdoc3.txt'); + $folder1 = $this->root->add_folder("New move folder"); + $this->assertNotError($newFolder); + if(PEAR::isError($newFolder)) return; + + $doc4 = $this->createDocument('Test Doc Four', 'testdoc4.txt', $folder1); + + // Add a folder + $targetFolder = $this->root->add_folder("New target folder"); + $this->assertNotError($newFolder); + if(PEAR::isError($newFolder)) return; + + $aItems = array($doc1, $doc2, $doc3, $folder1); + + // Copy documents and folder into target folder + $res = $this->bulk->move($aItems, $targetFolder, 'Testing bulk move'); + + $this->assertTrue(empty($res)); + + // Check document has been moved not copied + $detail = $doc1->get_detail(); + $this->assertFalse($detail['folder_id'] == $this->root->get_folderid()); + $this->assertTrue($detail['folder_id'] == $targetFolder->get_folderid()); + + // Check folder has been moved not copied + $this->assertFalse($folder1->get_parent_folder_id() == $this->root->get_folderid()); + $this->assertTrue($folder1->get_parent_folder_id() == $targetFolder->get_folderid()); + + // Check the documents copied + $listDocs = $targetFolder->get_listing(1, 'D'); + $this->assertTrue(count($listDocs) == 3); + + // Check the folder copied + $listFolders = $targetFolder->get_listing(1, 'F'); + $this->assertTrue(count($listFolders) == 1); + + // Check the document contained in the folder copied + $newFolderId = $listFolders[0]['id']; + $newFolder = $this->ktapi->get_folder_by_id($newFolderId); + $listSubDocs = $newFolder->get_listing(1, 'D'); + $this->assertTrue(count($listSubDocs) == 1); + + // Delete and expunge documents and folder + $this->deleteDocument($doc1); + $this->deleteDocument($doc2); + $this->deleteDocument($doc3); + $this->deleteDocument($doc4); + $targetFolder->delete('Testing bulk copy'); + $folder1->delete('Testing bulk copy'); + } + + /** + * Test the bulk checkout and cancel checkout functionality + */ + function testCheckout() + { + // Create documents + $doc1 = $this->createDocument('Test Doc One', 'testdoc1.txt'); + $doc2 = $this->createDocument('Test Doc Two', 'testdoc2.txt'); + $doc3 = $this->createDocument('Test Doc Three', 'testdoc3.txt'); + $folder1 = $this->root->add_folder("New test folder"); + $this->assertNotError($newFolder); + if(PEAR::isError($newFolder)) return; + + $doc4 = $this->createDocument('Test Doc Four', 'testdoc4.txt', $folder1); + + $aItems = array($doc1, $doc2, $doc3, $folder1); + + // Checkout documents and folder + $res = $this->bulk->checkout($aItems, 'Testing bulk checkout'); + + $this->assertTrue(empty($res)); + + $this->assertTrue($doc1->is_checked_out()); + $this->assertTrue($doc2->is_checked_out()); + $this->assertTrue($doc3->is_checked_out()); + $this->assertTrue($doc4->is_checked_out()); + + $res = $this->bulk->undo_checkout($aItems, 'Testing bulk undo / cancel checkout'); + + $this->assertTrue(empty($res)); + + $this->assertFalse($doc1->is_checked_out()); + $this->assertFalse($doc2->is_checked_out()); + $this->assertFalse($doc3->is_checked_out()); + $this->assertFalse($doc4->is_checked_out()); + + // Delete and expunge documents and folder + $this->deleteDocument($doc1); + $this->deleteDocument($doc2); + $this->deleteDocument($doc3); + $this->deleteDocument($doc4); + $folder1->delete('Testing bulk checkout'); + } + + /** + * Test the bulk immute functionality + */ + function testImmute() + { + // Create documents + $doc1 = $this->createDocument('Test Doc One', 'testdoc1.txt'); + $doc2 = $this->createDocument('Test Doc Two', 'testdoc2.txt'); + $doc3 = $this->createDocument('Test Doc Three', 'testdoc3.txt'); + $folder1 = $this->root->add_folder("New test folder"); + $this->assertNotError($newFolder); + if(PEAR::isError($newFolder)) return; + + $doc4 = $this->createDocument('Test Doc Four', 'testdoc4.txt', $folder1); + + $aItems = array($doc1, $doc2, $doc3, $folder1); + + // Immute documents + $res = $this->bulk->immute($aItems); + + $this->assertTrue(empty($res)); + + $this->assertTrue($doc1->isImmutable()); + $this->assertTrue($doc2->isImmutable()); + $this->assertTrue($doc3->isImmutable()); + $this->assertTrue($doc4->isImmutable()); + + // remove immutability for deletion + $doc1->unimmute(); + $doc2->unimmute(); + $doc3->unimmute(); + $doc4->unimmute(); + + // Delete and expunge documents and folder + $this->deleteDocument($doc1); + $this->deleteDocument($doc2); + $this->deleteDocument($doc3); + $this->deleteDocument($doc4); + $folder1->delete('Testing bulk checkout'); + } + + /** + * Test the bulk delete functionality + */ + function testDelete() + { + // Create documents + $doc1 = $this->createDocument('Test Doc One', 'testdoc1.txt'); + $doc2 = $this->createDocument('Test Doc Two', 'testdoc2.txt'); + $doc3 = $this->createDocument('Test Doc Three', 'testdoc3.txt'); + $folder1 = $this->root->add_folder("New test folder"); + $this->assertNotError($newFolder); + if(PEAR::isError($newFolder)) return; + + $doc4 = $this->createDocument('Test Doc Four', 'testdoc4.txt', $folder1); + + $aItems = array($doc1, $doc2, $doc3, $folder1); + + // Delete documents and folder + $res = $this->bulk->delete($aItems, 'Testing bulk delete'); + + $this->assertTrue(empty($res)); + + // Check documents have been deleted + $this->assertTrue($doc1->is_deleted()); + $this->assertTrue($doc2->is_deleted()); + $this->assertTrue($doc3->is_deleted()); + $this->assertTrue($doc4->is_deleted()); + + // Check folder has been deleted + $folder = $this->ktapi->get_folder_by_name('New test folder'); + $this->assertError($folder); + + // Expunge documents + $doc1->expunge(); + $doc2->expunge(); + $doc3->expunge(); + $doc4->expunge(); + } + + /** + * Test the bulk archive functionality + */ + function testArchive() + { + // Create documents + $doc1 = $this->createDocument('Test Doc One', 'testdoc1.txt'); + $doc2 = $this->createDocument('Test Doc Two', 'testdoc2.txt'); + $doc3 = $this->createDocument('Test Doc Three', 'testdoc3.txt'); + $folder1 = $this->root->add_folder("New test folder"); + $this->assertNotError($newFolder); + if(PEAR::isError($newFolder)) return; + + $doc4 = $this->createDocument('Test Doc Four', 'testdoc4.txt', $folder1); + + $aItems = array($doc1, $doc2, $doc3, $folder1); + + // Archive documents and folder + $res = $this->bulk->archive($aItems, 'Testing bulk archive'); + + $this->assertTrue(empty($res)); + + $document1 = $doc1->getObject(); + $this->assertTrue($document1->getStatusID() == 4); + $document4 = $doc4->getObject(); + $this->assertTrue($document4->getStatusID() == 4); + + // Restore for deletion + $doc1->restore(); + $doc2->restore(); + $doc3->restore(); + $doc4->restore(); + + // Delete and expunge documents and folder + $this->deleteDocument($doc1); + $this->deleteDocument($doc2); + $this->deleteDocument($doc3); + $this->deleteDocument($doc4); + $folder1->delete('Testing bulk archive'); + } + + /** + * Helper function to delete docs + */ + function deleteDocument($document) + { + $document->delete('Testing bulk actions'); + $document->expunge(); + } + + /** + * Helper function to create a document + */ + function createDocument($title, $filename, $folder = null) + { + if(is_null($folder)){ + $folder = $this->root; + } + + // Create a new document + $randomFile = $this->createRandomFile(); + $this->assertTrue(is_file($randomFile)); + + $document = $folder->add_document($title, $filename, 'Default', $randomFile); + $this->assertNotError($document); + + @unlink($randomFile); + if(PEAR::isError($document)) return false; + + return $document; + } + + /** + * Helper function to create a file + * + * @param unknown_type $content + * @return unknown + */ + function createRandomFile($content = 'this is some text') { + $temp = tempnam(dirname(__FILE__), 'myfile'); + file_put_contents($temp, $content); + return $temp; + } +} +?> \ No newline at end of file diff --git a/tests/runtests.php b/tests/runtests.php index 8946675..aae0685 100644 --- a/tests/runtests.php +++ b/tests/runtests.php @@ -6,18 +6,24 @@ class UnitTests extends TestSuite { function UnitTests() { $this->TestSuite('Unit tests'); + + // KTAPI $this->addFile('api/testAuthentication.php'); $this->addFile('api/testDocument.php'); $this->addFile('api/testFolder.php'); - $this->addFile('SQLFile/test_sqlfile.php'); - $this->addFile('cache/testCache.php'); - $this->addFile('config/testConfig.php'); - $this->addFile('document/testDocument.php'); - $this->addFile('document/testDocumentUtil.php'); + $this->addFile('api/testBulkActions.php'); + $this->addFile('api/testCollection.php'); + +// $this->addFile('SQLFile/test_sqlfile.php'); +// $this->addFile('cache/testCache.php'); +// $this->addFile('config/testConfig.php'); +// $this->addFile('document/testDocument.php'); +// $this->addFile('document/testDocumentUtil.php'); // $this->addFile('folder/testFolder.php'); // $this->addFile('browseutil/testBrowseUtil.php'); // $this->addFile('filelike/testStringFileLike.php'); + // Search (2) and indexing $this->addFile('documentProcessor/testExtracters.php'); // $this->addFile('documentProcessor/testIndexer.php'); $this->addFile('documentProcessor/testGuidInserter.php');