. * * 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 KTAPI * @version Version 0.9 */ require_once(KT_DIR . '/ktwebservice/KTDownloadManager.inc.php'); /** * API for the handling document operations within KnowledgeTree * * @author KnowledgeTree Team * @package KTAPI * @version 0.9 */ class KTAPI_Document extends KTAPI_FolderItem { /** * This is a reference to the internal document object. * * @access protected * @var object of Document */ var $document; /** * This is the id of the document. * * @access protected * @var int */ var $documentid; /** * This is a reference to the parent folder. * * @access protected * @var object of KTAPI_Folder */ var $ktapi_folder; /** * Gets the id of the current document * * @author KnowledgeTree Team * @access public * @return string The document id */ function get_documentid() { return $this->documentid; } /** * This is used to get a document based on document id. * * @author KnowledgeTree Team * @static * @access public * @param KTAPI $ktapi The ktapi object * @param int $documentid The document id * @return KTAPI_Document The document object */ function &get(&$ktapi, $documentid) { assert(!is_null($ktapi)); assert(is_a($ktapi, 'KTAPI')); assert(is_numeric($documentid)); $documentid += 0; $document = &Document::get($documentid); if (is_null($document) || PEAR::isError($document)) { return new KTAPI_Error(KTAPI_ERROR_DOCUMENT_INVALID,$document ); } $user = $ktapi->can_user_access_object_requiring_permission($document, KTAPI_PERMISSION_READ); if (is_null($user) || PEAR::isError($user)) { return $user; } $folderid = $document->getParentID(); if (!is_null($folderid)) { $ktapi_folder = &KTAPI_Folder::get($ktapi, $folderid); } else { $ktapi_folder = null; } // We don't do any checks on this folder as it could possibly be deleted, and is not required right now. return new KTAPI_Document($ktapi, $ktapi_folder, $document); } /** * Checks if a document has been deleted * * @author KnowledgeTree Team * @access public * @return boolean TRUE if deleted | FALSE if in a different state */ function is_deleted() { return ($this->document->getStatusID() == 3); } /** * Checks if the document is a shortcut * * @author KnowledgeTree Team * @access public * @return boolean TRUE if it is a shortcut | FALSE if not */ function is_shortcut() { return $this->document->isSymbolicLink(); } /** * Retrieves the shortcuts linking to this document * * @author KnowledgeTree Team * @access public * @return array The shortcuts linked to the document */ function get_shortcuts() { return $this->document->getSymbolicLinks(); } /** * This is the constructor for the KTAPI_Document * * @author KnowledgeTree Team * @access private * @param KTAPI $ktapi The KTAPI object * @param KTAPI_Folder $ktapi_folder The parent folder object * @param Document $document The internal document object * @return KTAPI_Document */ function KTAPI_Document(&$ktapi, &$ktapi_folder, &$document) { assert($ktapi instanceof KTAPI); //is_a($ktapi,'KTAPI')); assert(is_null($ktapi_folder) || $ktapi_folder instanceof KTAPI_Folder); //is_a($ktapi_folder,'KTAPI_Folder')); $this->ktapi = &$ktapi; $this->ktapi_folder = &$ktapi_folder; $this->document = &$document; $this->documentid = $document->getId(); } /** * This checks a document into the repository. * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * if($document->is_checked_out()){ * $document->checkin('filename.txt', 'Reason for checkin', '/tmp/filename'); * } * * * @author KnowledgeTree Team * @access public * @param string $filename The name of the file * @param string $reason The reason for checking the document in * @param string $tempfilename The location of the temporary file * @param bool $major_update Determines if the version number should have a major increment (+1) or a minor increment (+0.1) */ function checkin($filename, $reason, $tempfilename, $major_update=false) { if (!is_file($tempfilename)) { return new PEAR_Error('File does not exist.'); } $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WRITE); if (PEAR::isError($user)) { return $user; } if (!$this->document->getIsCheckedOut()) { return new PEAR_Error(KTAPI_ERROR_DOCUMENT_NOT_CHECKED_OUT); } $filename = KTUtil::replaceInvalidCharacters($filename); $options = array('major_update'=>$major_update); $currentfilename = $this->document->getFileName(); if ($filename != $currentfilename) { $options['newfilename'] = $filename; } DBUtil::startTransaction(); $result = KTDocumentUtil::checkin($this->document, $tempfilename, $reason, $user, $options); if (PEAR::isError($result)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$result); } DBUtil::commit(); KTUploadManager::temporary_file_imported($tempfilename); } /** * Removes the update notification for the document * * @author KnowledgeTree Team * @access public */ function removeUpdateNotification() { $sql = "DELETE FROM notifications WHERE data_int_1=$this->documentid AND data_str_1='ModifyDocument'"; DBUtil::runQuery($sql); } /** * Creates a link between two documents * * @author KnowledgeTree Team * @access public * @param KTAPI_Document $document The document object * @param string $type The link relationship type: depended on|Attachment|Reference|Copy|Default * @return PEAR_Error|void Returns nothing on success | a PEAR_Error object on failure * */ function link_document($document, $type) { $typeid = $this->ktapi->get_link_type_id($type); if (PEAR::isError($typeid)) { return $typeid; } $link = new DocumentLink($this->get_documentid(), $document->get_documentid(), $typeid ); $created = $link->create(); if ($created === false || PEAR::isError($created)) { return new PEAR_Error(_kt('Could not create link')); } } /** * Removes the link between two documents * * @author KnowledgeTree Team * @access public * @param KTAPI_Document $document The document object * @return PEAR_Error|void Returns nothing on success | a PEAR_Error object on failure */ function unlink_document($document) { $sql = "DELETE FROM document_link WHERE parent_document_id=$this->documentid AND child_document_id=$document->documentid"; $result = DBUtil::runQuery($sql); if (empty($result) || PEAR::isError($created)) { return new PEAR_Error(_kt('Could not remove link')); } } /** * Checks whether the document has been checked out. * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * if($document->is_checked_out()){ * continue; * }else{ * $document->checkout('Reason for document checkout'); * } * * * @author KnowledgeTree Team * @access public * @return boolean TRUE if checked out | FALSE if not */ function is_checked_out() { return ($this->document->getIsCheckedOut()); } /** * Cancels the checkout on a document * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * if($document->is_checked_out()){ * $document->undo_checkout('Reason for cancelling checkout'); * } * * * @author KnowledgeTree Team * @access public * @param string $reason The reason for cancelling * @return PEAR_Error|void Returns nothing on success | a PEAR_Error on failure */ function undo_checkout($reason) { $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WRITE); if (PEAR::isError($user)) { return $user; } if (!$this->document->getIsCheckedOut()) { return new PEAR_Error(KTAPI_ERROR_DOCUMENT_NOT_CHECKED_OUT); } DBUtil::startTransaction(); $this->document->setIsCheckedOut(0); $this->document->setCheckedOutUserID(-1); $res = $this->document->update(); if (($res === false) || PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res); } $oDocumentTransaction = new DocumentTransaction($this->document, $reason, 'ktcore.transactions.force_checkin'); $res = $oDocumentTransaction->create(); if (($res === false) || PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res); } DBUtil::commit(); } /** * Gets a list of linked documents * * @author KnowledgeTree Team * @access public * @return array|PEAR_Error Returns a list of linked documents on success | a PEAR_Error on failure */ function get_linked_documents() { $sql = " SELECT dl.child_document_id as document_id, dmv.name as title, dcv.size, w.name as workflow, ws.name as workflow_state, dlt.name as link_type, dtl.name as document_type, dcv.major_version, dcv.minor_version, d.oem_no FROM document_link dl INNER JOIN document_link_types dlt ON dl.link_type_id=dlt.id INNER JOIN documents d ON dl.child_document_id=d.id INNER JOIN document_metadata_version dmv ON d.metadata_version_id=dmv.id INNER JOIN document_content_version dcv ON dmv.content_version_id=dcv.id INNER JOIN document_types_lookup dtl ON dtl.id=dmv.document_type_id LEFT OUTER JOIN workflow_documents wd ON d.id=wd.document_id LEFT OUTER JOIN workflows w ON w.id=wd.workflow_id LEFT OUTER JOIN workflow_states ws ON wd.state_id=ws.id WHERE dl.parent_document_id=$this->documentid "; $rows = DBUtil::getResultArray($sql); if (PEAR::isError($rows)) { return $rows; } $result=array(); $read_permission = &KTPermission::getByName(KTAPI_PERMISSION_READ); $user = $this->ktapi->get_user(); foreach($rows as $row) { $document = Document::get($row['document_id']); if (PEAR::isError($document) || is_null($document)) { continue; } if(!KTPermissionUtil::userHasPermissionOnItem($user, $read_permission, $document)) { continue; } $oem_no = $row['oem_no']; if (empty($oem_no)) $oem_no = 'n/a'; $result[] = array( 'document_id'=>(int)$row['document_id'], 'custom_document_no'=>'n/a', 'oem_document_no'=>$oem_no, 'title'=> $row['title'], 'document_type'=> $row['document_type'], 'version'=> (float) ($row['major_version'] . '.' . $row['minor_version']), 'filesize'=>(int)$row['size'], 'workflow'=>empty($row['workflow'])?'n/a':$row['workflow'], 'workflow_state'=>empty($row['workflow_state'])?'n/a':$row['workflow_state'], 'link_type'=>empty($row['link_type'])?'unknown':$row['link_type'], ); } return $result; } /** * Checks out a document * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * $document->checkout('Reason for document checkout'); * if($document->is_checked_out()){ * continue; * } * * * @author KnowledgeTree Team * @access public * @param string $reason The reason for checking out the document * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function checkout($reason) { $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WRITE); if (PEAR::isError($user)) { return $user; } //if the document is checked-out by the current user, just return //as no need to check-out again BUT we do need to download //returning here will allow download, but skip check-out if ( ($this->document->getIsCheckedOut()) && ($this->document->getCheckedOutUserID() == $_SESSION['userID']) ) { return; } DBUtil::startTransaction(); $res = KTDocumentUtil::checkout($this->document, $reason, $user); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res); } DBUtil::commit(); } /** * Deletes a document from the folder. * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * $document->delete('Reason for deletion'); * * * @author KnowledgeTree Team * @access public * @param string $reason The reason for deleting the document * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function delete($reason) { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_DELETE); if (PEAR::isError($user)) { return $user; } if ($this->document->getIsCheckedOut()) { return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT); } DBUtil::startTransaction(); $res = KTDocumentUtil::delete($this->document, $reason); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res); } DBUtil::commit(); } /** * Changes the owner of a document and updates its permissions. * * @author KnowledgeTree Team * @access public * @param string $newusername The username of the new owner * @param string $reason The reason for changing the owner * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function change_owner($newusername, $reason='Changing of owner.') { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_CHANGE_OWNERSHIP); if (PEAR::isError($user)) { return $user; } DBUtil::startTransaction(); $user = &User::getByUserName($newusername); if (is_null($user) || PEAR::isError($user)) { return new KTAPI_Error('User could not be found',$user); } $newuserid = $user->getId(); $this->document->setOwnerID($newuserid); $res = $this->document->update(); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR ,$res ); } $res = KTPermissionUtil::updatePermissionLookup($this->document); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res ); } $oDocumentTransaction = new DocumentTransaction($this->document, $reason, 'ktcore.transactions.permissions_change'); $res = $oDocumentTransaction->create(); if (($res === false) || PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res ); } DBUtil::commit(); } /** * Copies the document from one folder to another. * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * $newFolder = $this->root->add_folder("New folder"); * $copyOfDoc = $document->copy($newFolder, 'Reason for copying document'); * * * @author KnowledgeTree Team * @access public * @param KTAPI_Folder $ktapi_target_folder The new parent folder where the document is being copied into * @param string $reason The reason for the copy * @param string $newname Optional. The title of the document to be used in the case of a name clash * @param string $newfilename Optional. The filename of the document to be used in the case of a name clash * @return KTAPI_Document|PEAR_Error Returns the new KTAPI Document object | a PEAR_Error on failure */ function copy(&$ktapi_target_folder, $reason, $newname=null, $newfilename=null) { assert(!is_null($ktapi_target_folder)); assert($ktapi_target_folder instanceof KTAPI_FOLDER); //is_a($ktapi_target_folder,'KTAPI_Folder')); if (empty($newname)) { $newname=null; } if (empty($newfilename)) { $newfilename=null; } $user = $this->ktapi->get_user(); if ($this->document->getIsCheckedOut()) { return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT); } $target_folder = &$ktapi_target_folder->get_folder(); $result = $this->can_user_access_object_requiring_permission($target_folder, KTAPI_PERMISSION_WRITE); if (PEAR::isError($result)) { return $result; } $name = $this->document->getName(); $clash = KTDocumentUtil::nameExists($target_folder, $name); if ($clash && !is_null($newname)) { $name = $newname; $clash = KTDocumentUtil::nameExists($target_folder, $name); } if ($clash) { if (is_null($newname)) { $name = KTDocumentUtil::getUniqueDocumentName($target_folder, $name); } else { return new PEAR_Error('A document with this title already exists in your chosen folder. ' . 'Please choose a different folder, or specify a new title for the copied document.'); } } $filename=$this->document->getFilename(); $clash = KTDocumentUtil::fileExists($target_folder, $filename); if ($clash && !is_null($newname)) { $filename = $newfilename; $clash = KTDocumentUtil::fileExists($target_folder, $filename); } if ($clash) { if (is_null($newfilename)) { $filename = KTDocumentUtil::getUniqueFilename($target_folder, $newfilename); } else { return new PEAR_Error('A document with this filename already exists in your chosen folder. ' . 'Please choose a different folder, or specify a new filename for the copied document.'); } } DBUtil::startTransaction(); $new_document = KTDocumentUtil::copy($this->document, $target_folder, $reason); if (PEAR::isError($new_document)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$new_document ); } $new_document->setName($name); $new_document->setFilename($filename); $res = $new_document->update(); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res ); } DBUtil::commit(); /* // FIXME do we need to refactor all trigger usage into the util function? $oKTTriggerRegistry = KTTriggerRegistry::getSingleton(); $aTriggers = $oKTTriggerRegistry->getTriggers('copyDocument', 'postValidate'); foreach ($aTriggers as $aTrigger) { $sTrigger = $aTrigger[0]; $oTrigger = new $sTrigger; $aInfo = array( 'document' => $new_document, 'old_folder' => $this->ktapi_folder->get_folder(), 'new_folder' => $target_folder, ); $oTrigger->setInfo($aInfo); $ret = $oTrigger->postValidate(); } */ return KTAPI_Document::get($this->ktapi, $new_document->getId()); } /** * Moves the document from one folder to another. * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * $newFolder = $this->root->add_folder("New folder"); * $document->move($newFolder, 'Reason for moving the document'); * * * @author KnowledgeTree Team * @access public * @param KTAPI_Folder $ktapi_target_folder The folder object where the document is being moved into * @param string $reason The reason for the move * @param string $newname Optional. The title of the document to be used in the case of a name clash * @param string $newfilename Optional. The filename of the document to be used in the case of a name clash * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function move(&$ktapi_target_folder, $reason, $newname=null, $newfilename=null) { assert(!is_null($ktapi_target_folder)); assert($ktapi_target_folder instanceof KTAPI_Folder); // is_a($ktapi_target_folder,'KTAPI_Folder')); if (empty($newname)) { $newname=null; } if (empty($newfilename)) { $newfilename=null; } $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_DOCUMENT_MOVE); if (PEAR::isError($user)) { return $user; } if ($this->document->getIsCheckedOut()) { return new PEAR_Error(KTAPI_ERROR_DOCUMENT_CHECKED_OUT); } $target_folder = $ktapi_target_folder->get_folder(); $result= $this->can_user_access_object_requiring_permission( $target_folder, KTAPI_PERMISSION_WRITE); if (PEAR::isError($result)) { return $result; } if (!KTDocumentUtil::canBeMoved($this->document, $error)) { if (PEAR::isError($error)) { return $error; } else { return new PEAR_Error('Document cannot be moved.'); } } $name = $this->document->getName(); $clash = KTDocumentUtil::nameExists($target_folder, $name); if ($clash && !is_null($newname)) { $name = $newname; $clash = KTDocumentUtil::nameExists($target_folder, $name); } if ($clash) { return new PEAR_Error('A document with this title already exists in your chosen folder. ' . 'Please choose a different folder, or specify a new title for the moved document.'); } $filename=$this->document->getFilename(); $clash = KTDocumentUtil::fileExists($target_folder, $filename); if ($clash && !is_null($newname)) { $filename = $newfilename; $clash = KTDocumentUtil::fileExists($target_folder, $filename); } if ($clash) { return new PEAR_Error('A document with this filename already exists in your chosen folder. ' . 'Please choose a different folder, or specify a new filename for the moved document.'); } DBUtil::startTransaction(); $res = KTDocumentUtil::move($this->document, $target_folder, $user, $reason); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res ); } $this->document->setName($name); $this->document->setFilename($filename); $res = $this->document->update(); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res ); } DBUtil::commit(); } /** * Changes the filename of the document. * If the filename contains any invalid characters they are replaced with a dash (-). For example: ?, *, %, \, / * * @author KnowledgeTree Team * @access public * @param string $newname The new filename * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function renameFile($newname) { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE); if (PEAR::isError($user)) { return $user; } $newname = KTUtil::replaceInvalidCharacters($newname); DBUtil::startTransaction(); $res = KTDocumentUtil::rename($this->document, $newname, $user); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res ); } DBUtil::commit(); } /** * Changes the document type of the document. * * @author KnowledgeTree Team * @access public * @param string $documenttype The new document type * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function change_document_type($documenttype) { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE); if (PEAR::isError($user)) { return $user; } $doctypeid = KTAPI::get_documenttypeid($documenttype); if (PEAR::isError($doctypeid)) { return $doctypeid; } if ($this->document->getDocumentTypeId() != $doctypeid) { // Get the current document type, fieldsets and metadata $iOldDocTypeID = $this->document->getDocumentTypeID(); $fieldsets = KTMetadataUtil::fieldsetsForDocument($this->document, $iOldDocTypeID); $mdlist = DocumentFieldLink::getByDocument($this->document); $field_values = array(); foreach ($mdlist as $oFieldLink) { $field_values[$oFieldLink->getDocumentFieldID()] = $oFieldLink->getValue(); } DBUtil::startTransaction(); $this->document->startNewMetadataVersion($user); $this->document->setDocumentTypeId($doctypeid); $res = $this->document->update(); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR,$res ); } // Ensure all values for fieldsets common to both document types are retained $fs_ids = array(); $doctype_fieldsets = KTFieldSet::getForDocumentType($doctypeid); foreach($doctype_fieldsets as $fieldset) { $fs_ids[] = $fieldset->getId(); } $MDPack = array(); foreach ($fieldsets as $oFieldset) { if ($oFieldset->getIsGeneric() || in_array($oFieldset->getId(), $fs_ids)) { $fields = $oFieldset->getFields(); foreach ($fields as $oField) { $val = isset($field_values[$oField->getId()]) ? $field_values[$oField->getId()] : ''; if (!empty($val)) { $MDPack[] = array($oField, $val); } } } } $core_res = KTDocumentUtil::saveMetadata($this->document, $MDPack, array('novalidate' => true)); if (PEAR::isError($core_res)) { DBUtil::rollback(); return $core_res; } $oKTTriggerRegistry = KTTriggerRegistry::getSingleton(); $aTriggers = $oKTTriggerRegistry->getTriggers('edit', 'postValidate'); foreach ($aTriggers as $aTrigger) { $sTrigger = $aTrigger[0]; $oTrigger = new $sTrigger; $aInfo = array( "document" => $this->document, "aOptions" => $packed, ); $oTrigger->setInfo($aInfo); $ret = $oTrigger->postValidate(); } DBUtil::commit(); } } /** * Changes the title of the document. * If the title contains any invalid characters they are replaced with a dash (-). For example: ?, *, %, \, / * * @author KnowledgeTree Team * @access public * @param string $newname The new document title * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function rename($newname) { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE); if (PEAR::isError($user)) { return $user; } $newname = KTUtil::replaceInvalidCharacters($newname); if ($this->document->getName() != $newname) { DBUtil::startTransaction(); $this->document->setName($newname); $res = $this->document->update(); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res); } DBUtil::commit(); } } /** * Sets the status of the document to 'archived'. * * @author KnowledgeTree Team * @access public * @param string $reason The reason for archiving the document * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function archive($reason) { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WRITE); if (PEAR::isError($user)) { 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(); $this->document->setStatusID(ARCHIVED); $res = $this->document->update(); if (($res === false) || PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $res); } $oDocumentTransaction = new DocumentTransaction($this->document, sprintf(_kt('Document archived: %s'), $reason), 'ktcore.transactions.update'); $oDocumentTransaction->create(); DBUtil::commit(); $oKTTriggerRegistry = KTTriggerRegistry::getSingleton(); $aTriggers = $oKTTriggerRegistry->getTriggers('archive', 'postValidate'); foreach ($aTriggers as $aTrigger) { $sTrigger = $aTrigger[0]; $oTrigger = new $sTrigger; $aInfo = array( 'document' => $this->document, ); $oTrigger->setInfo($aInfo); $ret = $oTrigger->postValidate(); } */ } /** * Starts a workflow on a document. * * @author KnowledgeTree Team * @access public * @param string $workflow The workflow being applied * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function start_workflow($workflow) { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW); if (PEAR::isError($user)) { return $user; } $workflowid = $this->document->getWorkflowId(); if (!empty($workflowid)) { return new PEAR_Error('A workflow is already defined.'); } $workflow = KTWorkflow::getByName($workflow); if (is_null($workflow) || PEAR::isError($workflow)) { return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $workflow); } DBUtil::startTransaction(); $result = KTWorkflowUtil::startWorkflowOnDocument($workflow, $this->document); if (is_null($result) || PEAR::isError($result)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $result); } DBUtil::commit(); } /** * This deletes the workflow on the document. * * @author KnowledgeTree Team * @access public * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function delete_workflow() { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW); if (PEAR::isError($user)) { return $user; } $workflowid=$this->document->getWorkflowId(); if (empty($workflowid)) { return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS); } DBUtil::startTransaction(); $result = KTWorkflowUtil::startWorkflowOnDocument(null, $this->document); if (is_null($result) || PEAR::isError($result)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID,$result); } DBUtil::commit(); } /** * This performs a transition to a new state of the workflow on the document * * @author KnowledgeTree Team * @access public * @param string $transition The transition to perform * @param string $reason The reason for transitioning the document to a new state * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function perform_workflow_transition($transition, $reason) { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW); if (PEAR::isError($user)) { return $user; } $workflowid=$this->document->getWorkflowId(); if (empty($workflowid)) { return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS); } $transition = &KTWorkflowTransition::getByName($transition); if (is_null($transition) || PEAR::isError($transition)) { return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $transition); } DBUtil::startTransaction(); $result = KTWorkflowUtil::performTransitionOnDocument($transition, $this->document, $user, $reason); if (is_null($result) || PEAR::isError($result)) { DBUtil::rollback(); return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $transition); } DBUtil::commit(); } /** * This returns all metadata for the document. * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * $metadata = $document->get_metadata(); * foreach($metadata as $fieldset){ * echo '

Fieldset: '.$fieldset['fieldset']; * * foreach($fieldset['fields'] as $field){ * echo '
Field name: '.$field['name'] . ' Value: '. $field['value']; * } * } *
* * @author KnowledgeTree Team * @access public * @return array An array of metadata fieldsets and fields */ function get_metadata() { $doctypeid = $this->document->getDocumentTypeID(); $fieldsets = (array) KTMetadataUtil::fieldsetsForDocument($this->document, $doctypeid); if (is_null($fieldsets) || PEAR::isError($fieldsets)) { return array(); } $results = array(); foreach ($fieldsets as $fieldset) { if ($fieldset->getIsConditional()) { /* this is not implemented...*/ continue; } $fields = $fieldset->getFields(); $result = array('fieldset' => $fieldset->getName(), 'description' => $fieldset->getDescription()); $fieldsresult = array(); foreach ($fields as $field) { $value = ''; $fieldvalue = DocumentFieldLink::getByDocumentAndField($this->document, $field); if (!is_null($fieldvalue) && (!PEAR::isError($fieldvalue))) { $value = $fieldvalue->getValue(); } // Old //$controltype = 'string'; // Replace with true $controltype = strtolower($field->getDataType()); if ($field->getHasLookup()) { $controltype = 'lookup'; if ($field->getHasLookupTree()) { $controltype = 'tree'; } } // Options - Required for Custom Properties $options = array(); if ($field->getInetLookupType() == 'multiwithcheckboxes' || $field->getInetLookupType() == 'multiwithlist') { $controltype = 'multiselect'; } switch ($controltype) { case 'lookup': $selection = KTAPI::get_metadata_lookup($field->getId()); break; case 'tree': $selection = KTAPI::get_metadata_tree($field->getId()); break; case 'large text': $options = array( 'ishtml' => $field->getIsHTML(), 'maxlength' => $field->getMaxLength() ); $selection= array(); break; case 'multiselect': $selection = KTAPI::get_metadata_lookup($field->getId()); $options = array( 'type' => $field->getInetLookupType() ); break; default: $selection= array(); } $fieldsresult[] = array( 'name' => $field->getName(), 'required' => $field->getIsMandatory(), 'value' => $value == '' ? 'n/a' : $value, 'blankvalue' => $value=='' ? '1' : '0', 'description' => $field->getDescription(), 'control_type' => $controltype, 'selection' => $selection, 'options' => $options, ); } $result['fields'] = $fieldsresult; $results [] = $result; } return $results; } /** * Gets a simple array of document metadata fields * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * $metadata = $document->get_packed_metadata(); * foreach($metadata as $field){ * echo '

Fieldset: ' . $field[0]->getParentFieldset(); * echo '
Field name: ' .$field[0]->getName(); * echo ' Value: ' . $field[1]; * } *
* * @author KnowledgeTree Team * @access public * @param array $metadata The full metadata fieldsets and fields * @return array An array of metadata field object and value pairs */ function get_packed_metadata($metadata=null) { global $default; if (is_null($metadata)) { $metadata = $this->get_metadata(); } $packed = array(); foreach($metadata as $fieldset_metadata) { if (is_array($fieldset_metadata)) { $fieldsetname=$fieldset_metadata['fieldset']; $fields=$fieldset_metadata['fields']; } elseif ($fieldset_metadata instanceof stdClass) //is_a($fieldset_metadata, 'stdClass')) { $fieldsetname=$fieldset_metadata->fieldset; $fields=$fieldset_metadata->fields; } else { $default->log->debug("unexpected fieldset type"); continue; } $fieldset = KTFieldset::getByName($fieldsetname); if (is_null($fieldset) || PEAR::isError($fieldset) || $fieldset instanceof KTEntityNoObjects) //is_a($fieldset, 'KTEntityNoObjects')) { $default->log->debug("could not resolve fieldset: $fieldsetname for document id: $this->documentid"); // exit graciously continue; } foreach($fields as $fieldinfo) { if (is_array($fieldinfo)) { $fieldname = $fieldinfo['name']; $value = $fieldinfo['value']; } elseif ($fieldinfo instanceof stdClass) // is_a($fieldinfo, 'stdClass')) { $fieldname = $fieldinfo->name; $value = $fieldinfo->value; } else { $default->log->debug("unexpected fieldinfo type"); continue; } $field = DocumentField::getByFieldsetAndName($fieldset, $fieldname); if (is_null($field) || PEAR::isError($field) || is_a($field, 'KTEntityNoObjects')) { $default->log->debug("Could not resolve field: $fieldname on fieldset $fieldsetname for document id: $this->documentid"); // exit graciously continue; } $packed[] = array($field, $value); } } return $packed; } /** * This updates the metadata on the document. This includes the 'title'. * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * $metadata = $document->get_metadata(); * foreach($metadata as $key => $fieldset){ * if($fieldset['fieldset'] == 'XYZ'){ * * foreach($fieldset['fields'] as $k => $field){ * if($field['name'] == 'ABC'){ * $metadata[$key][fields][$k]['value'] = 'new value'; * } * } * } * } * * $res = $document->update_metadata($metadata); * * * @author KnowledgeTree Team * @access public * @param array This is an array containing the metadata to be associated with the document. * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function update_metadata($metadata) { global $default; if (empty($metadata)) { return; } $packed = $this->get_packed_metadata($metadata); DBUtil::startTransaction(); $user = $this->ktapi->get_user(); $this->document->setLastModifiedDate(getCurrentDateTime()); $this->document->setModifiedUserId($user->getId()); // Update the content version / document version if($default->updateContentVersion){ $this->document->startNewContentVersion($user); $this->document->setMinorVersionNumber($this->document->getMinorVersionNumber()+1); }else { $this->document->startNewMetadataVersion($user); } $res = $this->document->update(); if (PEAR::isError($res)) { DBUtil::rollback(); return new KTAPI_Error('Unexpected failure updating document', $res); } $result = KTDocumentUtil::saveMetadata($this->document, $packed, array('novalidate'=>true)); if (is_null($result)) { DBUtil::rollback(); return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR . ': Null result returned but not expected.'); } if (PEAR::isError($result)) { DBUtil::rollback(); return new KTAPI_Error('Unexpected validation failure', $result); } DBUtil::commit(); $oKTTriggerRegistry = KTTriggerRegistry::getSingleton(); $aTriggers = $oKTTriggerRegistry->getTriggers('edit', 'postValidate'); foreach ($aTriggers as $aTrigger) { $sTrigger = $aTrigger[0]; $oTrigger = new $sTrigger; $aInfo = array( "document" => $this->document, "aOptions" => $packed, ); $oTrigger->setInfo($aInfo); $ret = $oTrigger->postValidate(); } } /** * This updates the system metadata on the document. * * @author KnowledgeTree Team * @access public * @param array $sysdata The system metadata to be applied * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function update_sysdata($sysdata) { global $default; if (empty($sysdata)) { return; } $owner_mapping = array( 'created_by'=>'creator_id', 'modified_by'=>'modified_user_id', 'owner'=>'owner_id' ); $documents = array(); $document_content = array(); $indexContent = null; $uniqueOemNo = false; foreach($sysdata as $rec) { if (is_object($rec)) { $name = $rec->name; $value = sanitizeForSQL($rec->value); } elseif(is_array($rec)) { $name = $rec['name']; $value = sanitizeForSQL($rec['value']); } else { // just ignore continue; } switch(strtolower($name)) { case 'unique_oem_document_no': $documents['oem_no'] = $value; $uniqueOemNo = true; break; case 'oem_document_no': $documents['oem_no'] = $value; break; case 'index_content': $indexContent = $value; break; case 'created_date': if (!empty($value)) $documents['created'] = $value; break; case 'modified_date': if (!empty($value)) $documents['modified'] = $value; break; case 'is_immutable': $documents['immutable'] = in_array(strtolower($value), array('1','true','on','yes'))?'1':'0'; break; case 'filename': $value = KTUtil::replaceInvalidCharacters($value); $document_content['filename'] = $value; break; case 'major_version': $document_content['major_version'] = $value; break; case 'minor_version': $document_content['minor_version'] = $value; break; case 'version': list($major_version, $minor_version) = explode('.', $value); $document_content['major_version'] = $major_version; $document_content['minor_version'] = $minor_version; break; case 'mime_type': $sql = "select id from mime_types where mimetypes='$value'"; $value = DBUtil::getResultArray($sql); if (PEAR::isError($value)) { $default->log->error("Problem resolving mime type '$value' for document id $this->documentid. Reason: " . $value->getMessage()); return $value; } if (count($value) == 0) { $default->log->error("Problem resolving mime type '$value' for document id $this->documentid. None found."); break; } $value = $value[0]['id']; $document_content['mime_id'] = $value; break; case 'owner': case 'created_by': case 'modified_by': $sql = "select id from users where name='$value'"; $userId = DBUtil::getResultArray($sql); if (PEAR::isError($userId)) { $default->log->error("Problem resolving user '$value' for document id $this->documentid. Reason: " . $userId->getMessage()); return $userId; } if (empty($userId)) { $sql = "select id from users where username='$value'"; $userId = DBUtil::getResultArray($sql); if (PEAR::isError($userId)) { $default->log->error("Problem resolving username '$value' for document id $this->documentid. Reason: " . $userId->getMessage()); return $userId; } } if (empty($userId)) { $default->log->error("Problem resolving user based on '$value' for document id $this->documentid. No user found"); // if not found, not much we can do break; } $userId=$userId[0]; $userId=$userId['id']; $name = $owner_mapping[$name]; $documents[$name] = $userId; break; default: $default->log->error("Problem updating field '$name' with value '$value' for document id $this->documentid. Field is unknown."); // TODO: we should do some logging //return new PEAR_Error('Unexpected field: ' . $name); } } if (count($documents) > 0) { $sql = "UPDATE documents SET "; $i=0; foreach($documents as $name=>$value) { if ($i++ > 0) $sql .= ","; $value = sanitizeForSQL($value); $sql .= "$name='$value'"; } $sql .= " WHERE id=$this->documentid"; $result = DBUtil::runQuery($sql); if (PEAR::isError($result)) { return $result; } if ($uniqueOemNo) { $oem_no = sanitizeForSQL($documents['oem_no']); $sql = "UPDATE documents SET oem_no=null WHERE oem_no = '$oem_no' AND id != $this->documentid"; $result = DBUtil::runQuery($sql); } } if (count($document_content) > 0) { $content_id = $this->document->getContentVersionId(); $sql = "UPDATE document_content_version SET "; $i=0; foreach($document_content as $name=>$value) { if ($i++ > 0) $sql .= ","; $value = sanitizeForSQL($value); $sql .= "$name='$value'"; } $sql .= " WHERE id=$content_id"; $result = DBUtil::runQuery($sql); if (PEAR::isError($result)) { return $result; } } if (!is_null($indexContent)) { $indexer = Indexer::get(); $result = $indexer->diagnose(); if (empty($result)) { $indexer->updateDocumentIndex($this->documentid, $indexContent); } else { $default->log->error("Problem updating index with value '$value' for document id $this->documentid. Problem with indexer."); } } } /** * Clears the cached data on the document and refreshes the document object. * * @author KnowledgeTree Team * @access public */ function clearCache() { // TODO: we should only clear the cache for the document we are working on // this is a quick fix but not optimal!! $metadataid = $this->document->getMetadataVersionId(); $contentid = $this->document->getContentVersionId(); $cache = KTCache::getSingleton(); $cache->remove('KTDocumentMetadataVersion/id', $metadataid); $cache->remove('KTDocumentContentVersion/id', $contentid); $cache->remove('KTDocumentCore/id', $this->documentid); $cache->remove('Document/id', $this->documentid); unset($GLOBALS['_OBJECTCACHE']['KTDocumentMetadataVersion'][$metadataid]); unset($GLOBALS['_OBJECTCACHE']['KTDocumentContentVersion'][$contentid]); unset($GLOBALS['_OBJECTCACHE']['KTDocumentCore'][$this->documentid]); $this->document = &Document::get($this->documentid); } /** * Merge new metadata with previous metadata version * * @author KnowledgeTree Team * @access public * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function mergeWithLastMetadataVersion() { // keep latest metadata version $metadata_version = $this->document->getMetadataVersion(); if ($metadata_version == 0) { // this could theoretically happen in the case we are updating metadata and sysdata, but no metadata fields are specified. return; } $metadata_id = $this->document->getMetadataVersionId(); // get previous version $sql = "SELECT id, metadata_version FROM document_metadata_version WHERE id<$metadata_id AND document_id=$this->documentid order by id desc"; $old = DBUtil::getResultArray($sql); if (is_null($old) || PEAR::isError($old)) { return new PEAR_Error('Previous version could not be resolved'); } // only interested in the first one $old=$old[0]; $old_metadata_id = $old['id']; $old_metadata_version = $old['metadata_version']; DBUtil::startTransaction(); // delete previous metadata version $sql = "DELETE FROM document_metadata_version WHERE id=$old_metadata_id"; $rs = DBUtil::runQuery($sql); if (PEAR::isError($rs)) { DBUtil::rollback(); return $rs; } // make latest equal to previous $sql = "UPDATE document_metadata_version SET metadata_version=$old_metadata_version WHERE id=$metadata_id"; $rs = DBUtil::runQuery($sql); if (PEAR::isError($rs)) { DBUtil::rollback(); return $rs; } $sql = "UPDATE documents SET metadata_version=$old_metadata_version WHERE id=$this->documentid"; $rs = DBUtil::runQuery($sql); if (PEAR::isError($rs)) { DBUtil::rollback(); return $rs; } DBUtil::commit(); $this->clearCache(); } /** * This returns the workflow transitions available for the user on the document * * @author KnowledgeTree Team * @access public * @return array|PEAR_Error Array of the workflow transitions | a PEAR_Error on failure */ function get_workflow_transitions() { $user = $this->can_user_access_object_requiring_permission( $this->document, KTAPI_PERMISSION_WORKFLOW); if (PEAR::isError($user)) { return $user; } $workflowid=$this->document->getWorkflowId(); if (empty($workflowid)) { return array(); } $result = array(); $transitions = KTWorkflowUtil::getTransitionsForDocumentUser($this->document, $user); if (is_null($transitions) || PEAR::isError($transitions)) { return new KTAPI_Error(KTAPI_ERROR_WORKFLOW_INVALID, $transitions); } foreach($transitions as $transition) { $result[] = $transition->getName(); } return $result; } /** * This returns the current workflow state * * @author KnowledgeTree Team * @access public * @return string Returns the name of the state | a PEAR_Error on failure */ function get_workflow_state() { $user = $this->can_user_access_object_requiring_permission($this->document, KTAPI_PERMISSION_WORKFLOW); if (PEAR::isError($user)) { return $user; } $workflowid=$this->document->getWorkflowId(); if (empty($workflowid)) { return new PEAR_Error(KTAPI_ERROR_WORKFLOW_NOT_IN_PROGRESS); } $result = array(); $state = KTWorkflowUtil::getWorkflowStateForDocument($this->document); if (is_null($state) || PEAR::isError($state)) { return new PEAR_Error(KTAPI_ERROR_WORKFLOW_INVALID); } $statename = $state->getName(); return $statename; } /** * Get the available permissions on the document. * R = read, W = write, E = edit - if the document is checked out by the user. * The method assumes read permissions is available. * * @author KnowledgeTree Team * @access public * @param Document $document The internal document object * @return string The available permissions */ function get_permission_string($document) { $perms = 'R'; if (Permission::userHasDocumentWritePermission($document)) { $perms .= 'W'; $user_id = $_SESSION['userID']; $co_user_id = $document->getCheckedOutUserID(); if (!empty($co_user_id) && ($user_id == $co_user_id)) { $perms .= 'E'; } } return $perms; } /** * This returns detailed information on the document. * * @author KnowledgeTree Team * @access public * @return array The document information */ function get_detail() { global $default; // make sure we ge tthe latest $this->clearCache(); $config = KTConfig::getSingleton(); $wsversion = $config->get('webservice/version', LATEST_WEBSERVICE_VERSION); $detail = array(); $document = $this->document; // get the document id $detail['document_id'] = (int) $document->getId(); $oem_document_no = null; if ($wsversion >= 2) { $oem_document_no = $document->getOemNo(); } if (empty($oem_document_no)) { $oem_document_no = 'n/a'; } $detail['custom_document_no'] = 'n/a'; $detail['oem_document_no'] = $oem_document_no; // get the title $detail['title'] = $document->getName(); // get the document type $documenttypeid=$document->getDocumentTypeID(); $documenttype = '* unknown *'; if (is_numeric($documenttypeid)) { $dt = DocumentType::get($documenttypeid); if (!is_null($dt) && !PEAR::isError($dt)) { $documenttype=$dt->getName(); } } $detail['document_type'] = $documenttype; // get the filename $detail['filename'] = $document->getFilename(); // get the filesize $detail['filesize'] = (int) $document->getFileSize(); // get the folder id $detail['folder_id'] = (int) $document->getFolderID(); // get the creator $userid = $document->getCreatorID(); $username='n/a'; if (is_numeric($userid)) { $username = '* unknown *'; $user = User::get($userid); if (!is_null($user) && !PEAR::isError($user)) { $username = $user->getName(); } } $detail['created_by'] = $username; // get the creation date $detail['created_date'] = $document->getCreatedDateTime(); // get the checked out user $userid = $document->getCheckedOutUserID(); $username='n/a'; if (is_numeric($userid)) { $username = '* unknown *'; $user = User::get($userid); if (!is_null($user) && !PEAR::isError($user)) { $username = $user->getName(); } } $detail['checked_out_by'] = $username; // get the checked out date list($major, $minor, $fix) = explode('.', $default->systemVersion); if ($major == 3 && $minor >= 5) { $detail['checked_out_date'] = $document->getCheckedOutDate(); } else { $detail['checked_out_date'] = $detail['modified_date']; } if (is_null($detail['checked_out_date'])) $detail['checked_out_date'] = 'n/a'; // get the modified user $userid = $document->getModifiedUserId(); $username='n/a'; if (is_numeric($userid)) { $username = '* unknown *'; $user = User::get($userid); if (!is_null($user) && !PEAR::isError($user)) { $username = $user->getName(); } } $detail['modified_by'] = $detail['updated_by'] = $username; // get the modified date $detail['updated_date'] = $detail['modified_date'] = $document->getLastModifiedDate(); // get the owner $userid = $document->getOwnerID(); $username='n/a'; if (is_numeric($userid)) { $username = '* unknown *'; $user = User::get($userid); if (!is_null($user) && !PEAR::isError($user)) { $username = $user->getName(); } } $detail['owned_by'] = $username; // get the version $detail['version'] = $document->getVersion(); if ($wsversion >= 2) { $detail['version'] = (float) $detail['version']; } //get the content_id $detail['content_id'] = $document->getContentVersionId(); //might be unset at the bottom in case of old webservice version //make sure we're using the real document for this one $this->document->switchToRealCore(); $detail['linked_document_id'] = $document->getLinkedDocumentId(); $this->document->switchToLinkedCore(); // check immutability $detail['is_immutable'] = (bool) $document->getImmutable(); // check permissions $detail['permissions'] = KTAPI_Document::get_permission_string($document); // get workflow name $workflowid = $document->getWorkflowId(); $workflowname='n/a'; if (is_numeric($workflowid)) { $workflow = KTWorkflow::get($workflowid); if (!is_null($workflow) && !PEAR::isError($workflow)) { $workflowname = $workflow->getName(); } } $detail['workflow'] = $workflowname; // get the workflow state $stateid = $document->getWorkflowStateId(); $workflowstate = 'n/a'; if (is_numeric($stateid)) { $state = KTWorkflowState::get($stateid); if (!is_null($state) && !PEAR::isError($state)) { $workflowstate = $state->getName(); } } $detail['workflow_state']=$workflowstate; // get the full path $detail['full_path'] = '/' . $this->document->getFullPath(); // get mime info $mimetypeid = $document->getMimeTypeID(); $detail['mime_type'] =KTMime::getMimeTypeName($mimetypeid); $detail['mime_icon_path'] =KTMime::getIconPath($mimetypeid); $detail['mime_display'] =KTMime::getFriendlyNameForString($detail['mime_type']); // get the storage path $detail['storage_path'] = $document->getStoragePath(); if ($wsversion >= 2) { unset($detail['updated_by']); unset($detail['updated_date']); } if($wsversion < 3){ unset($detail['linked_document_id']); } return $detail; } /** * Gets the title of the document * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * $title = $document->get_title(); * * * @author KnowledgeTree Team * @access public * @return string The document title */ function get_title() { return $this->document->getDescription(); } /** * Gets the url which can be used to download the document. * * @param int $version Not implemented. The content version of the document */ function get_download_url($version = null) { $session = $this->ktapi->get_session(); // Create the url that can be used to download the document $download_manager = new KTDownloadManager(); $download_manager->set_session($session->session); $download_manager->cleanup(); $url = $download_manager->allow_download($this); // Log the transaction $this->download(); return $url; } /** * Logs the document transaction for a download. * * @author KnowledgeTree Team * @access public */ function download() { $storage =& KTStorageManagerUtil::getSingleton(); $options = array(); $oDocumentTransaction = new DocumentTransaction($this->document, 'Document downloaded', 'ktcore.transactions.download', $aOptions); $oDocumentTransaction->create(); } /** * Function to fetch the actual file content of a document * * @return $content the document file content */ function get_document_content() { // fetch the content $content = KTDocumentUtil::getDocumentContent($this->document); // TODO what if the file could not be found? // Log the transaction $this->download(); // return the document content return $content; } /** * This returns the transaction history for the document. * * @author KnowledgeTree Team * @access public * @return array The list of transactions | a PEAR_Error on failure */ function get_transaction_history() { $sQuery = 'SELECT DTT.name AS transaction_name, U.name AS username, DT.version AS version, DT.comment AS comment, DT.datetime AS datetime ' . 'FROM ' . KTUtil::getTableName('document_transactions') . ' AS DT INNER JOIN ' . KTUtil::getTableName('users') . ' AS U ON DT.user_id = U.id ' . 'INNER JOIN ' . KTUtil::getTableName('transaction_types') . ' AS DTT ON DTT.namespace = DT.transaction_namespace ' . 'WHERE DT.document_id = ? ORDER BY DT.datetime DESC'; $aParams = array($this->documentid); $transactions = DBUtil::getResultArray(array($sQuery, $aParams)); if (is_null($transactions) || PEAR::isError($transactions)) { return new KTAPI_Error(KTAPI_ERROR_INTERNAL_ERROR, $transactions ); } $config = KTConfig::getSingleton(); $wsversion = $config->get('webservice/version', LATEST_WEBSERVICE_VERSION); foreach($transactions as $key=>$transaction) { $transactions[$key]['version'] = (float) $transaction['version']; } return $transactions; } /** * This returns the version history on the document. * * @author KnowledgeTree Team * @access public * @return array The version history */ function get_version_history() { $metadata_versions = KTDocumentMetadataVersion::getByDocument($this->document); $config = KTConfig::getSingleton(); $wsversion = $config->get('webservice/version', LATEST_WEBSERVICE_VERSION); $versions = array(); foreach ($metadata_versions as $version) { $document = &Document::get($this->documentid, $version->getId()); $version = array(); $userid = $document->getModifiedUserId(); $user = User::get($userid); $username = 'Unknown'; if (!PEAR::isError($user)) { $username = is_null($user)?'n/a':$user->getName(); } $version['user'] = $username; $version['metadata_version'] = $document->getMetadataVersion(); $version['content_version'] = $document->getVersion(); if ($wsversion >= 2) { $version['metadata_version'] = (int) $version['metadata_version']; $version['content_version'] = (float) $version['content_version']; } $versions[] = $version; } return $versions; } /** * This expunges a document from the system. * * * $ktapi = new KTAPI(); * $session = $ktapi->start_system_session(); * $document = $ktapi->get_document_by_id($documentid); * if($document->is_deleted()){ * $document->expunge(); * } * * * @author KnowledgeTree Team * @access public * @return void|PEAR_Error Returns nothing on success | a PEAR_Error on failure */ function expunge() { if ($this->document->getStatusID() != 3) { return new PEAR_Error('You should not purge this'); } DBUtil::startTransaction(); $transaction = new DocumentTransaction($this->document, "Document expunged", 'ktcore.transactions.expunge'); $transaction->create(); $this->document->delete(); $this->document->cleanupDocumentData($this->documentid); $storage =& KTStorageManagerUtil::getSingleton(); $result= $storage->expunge($this->document); DBUtil::commit(); } /** * Restores a deleted document * * @author KnowledgeTree Team * @access public */ function restore() { DBUtil::startTransaction(); $storage =& KTStorageManagerUtil::getSingleton(); $folder = Folder::get($this->document->getRestoreFolderId()); if (PEAR::isError($folder)) { $this->document->setFolderId(1); $folder = Folder::get(1); } else { $this->document->setFolderId($this->document->getRestoreFolderId()); } $storage->restore($this->document); $this->document->setStatusId(LIVE); $this->document->setPermissionObjectId($folder->getPermissionObjectId()); $res = $this->document->update(); $res = KTPermissionUtil::updatePermissionLookup($this->document); $user = $this->ktapi->get_user(); $oTransaction = new DocumentTransaction($this->document, 'Restored from deleted state by ' . $user->getName(), 'ktcore.transactions.update'); $oTransaction->create(); DBUtil::commit(); } /** * Returns the internal document object * * @author KnowledgeTree Team * @access public * @return Document The document object */ public function getObject() { return $this->document; } /** * Get the role allocation for the document * * @return KTAPI_RoleAllocation Instance of the role allocation object */ public function getRoleAllocation() { $allocation = KTAPI_RoleAllocation::getAllocation($this->ktapi, $this); return $allocation; } /** * Get the permission allocation for the document * * @return KTAPI_PermissionAllocation Instance of the permission allocation object */ public function getPermissionAllocation() { $allocation = KTAPI_PermissionAllocation::getAllocation($this->ktapi, $this); return $allocation; } /** * Checks if the user is subscribed to the document * * @author KnowledgeTree Team * @access public * @return bool $result TRUE if subscribed | FALSE if not */ public function isSubscribed() { $subscriptionType = SubscriptionEvent::subTypes('Document'); $user = $this->ktapi->get_user(); $document = $this->document; $result = Subscription::exists($user->getId(), $document->getId(), $subscriptionType); return $result; } /** * Removes the users subscription to the document * * @author KnowledgeTree Team * @access public * @return boolean|object $result SUCCESS Boolean result of operation | FAILURE - a pear error object */ public function unsubscribe() { if (!$this->isSubscribed()) { return TRUE; } $subscriptionType = SubscriptionEvent::subTypes('Document'); $user = $this->ktapi->get_user(); $document = $this->document; $subscription = & Subscription::getByIDs($user->getId(), $document->getId(), $subscriptionType); $result = $subscription->delete(); if(PEAR::isError($result)){ return $result->getMessage(); } if($result){ return $result; } return $_SESSION['errorMessage']; } /** * Subscribes the user to the document * * @author KnowledgeTree Team * @access public * @return boolean|object $result SUCCESS Boolean result of operation | FAILURE - a pear error object */ public function subscribe() { if ($this->isSubscribed()) { return TRUE; } $subscriptionType = SubscriptionEvent::subTypes('Document'); $user = $this->ktapi->get_user(); $document = $this->document; $subscription = new Subscription($user->getId(), $document->getId(), $subscriptionType); $result = $subscription->create(); if(PEAR::isError($result)){ return $result->getMessage(); } if($result){ return $result; } return $_SESSION['errorMessage']; } /** * Checks if the document is immutable * * @author KnowledgeTree Team * @access public * @return bool TRUE if it is immutable | FALSE if not */ public function isImmutable() { return $this->document->getImmutable(); } /** * Sets a document to be immutable * * @author KnowledgeTree Team * @access public */ 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(); } /** * Removes the immutability of a document * * @author KnowledgeTree Team * @access public */ public function unimmute() { $this->document->setImmutable(false); $this->document->update(); } /** * Emails a document as an attachment or hyperlink to a list of users, groups or external email addresses. * In the case of external addresses, if a hyperlink is used then a timed download link (via webservices) is sent * allowing the recipient a window period in which to download the document. * The period is set through the webservices config option webservice/downloadExpiry. Defaults to 30 minutes. * * @author KnowledgeTree Team * @access public * @param array $members The email recipients - KTPAI_Users, KTAPI_Groups or email addresses * @param string $comment Content to be appended to the email * @param bool $attachDocument TRUE if document is an attachment | FALSE if using a hyperlink to the document * * NOTE this function requires that the Email Plugin be active. * It seems that it is possible for this to be unintentionally turned off during a plugin re-read. */ public function email($members, $comment, $attachDocument = true) { // check for active email plugin if (!KTPluginUtil::pluginIsActive('ktstandard.email.plugin')) { return new PEAR_Error('Email Plugin is not active'); } if (empty($members)) { return new PEAR_Error('No recipients specified'); } $userIds = array(); $groupIds = array(); $emailAddrs = array(); foreach($members as $member) { if ($member instanceof KTAPI_User) { $userIds[] = $member->Id; } else if ($member instanceof KTAPI_Group) { $groupIds[] = $member->Id; } else if (is_string($member)) { $emailAddrs[] = $member; } } $config = KTConfig::getSingleton(); $allowAttachment = $config->get('email/allowAttachment', false); $allowEmailAddresses = $config->get('email/allowEmailAddresses', false); // if attachments aren't allowed, set $attachDocument to false if(!$allowAttachment) { $attachDocument = false; } // If sending to external email addresses is not allowed - set array of external recipients to empty if(!$allowEmailAddresses) { $emailAddrs = array(); } $emailErrors = array(); $userEmails = array(); $listEmails = array(); sendGroupEmails($groupIds, $userEmails, $emailErrors); sendUserEmails($userIds, $userEmails, $emailErrors); if ($attachDocument) { sendManualEmails($emailAddrs, $userEmails, $emailErrors); } else { sendExternalEmails($emailAddrs, $this->documentid, $this->get_title(), $comment, $emailErrors); } if(empty($userEmails)) { return; } $listEmails = array_keys($userEmails); sendEmail($listEmails, $this->documentid, $this->get_title(), $comment, (boolean)$attachDocument, $emailErrors); } /** * Get a list of Documents * * @param String Where clause (not required) * @return Array array of Documents objects, false otherwise. */ static public function getList($whereClause = null) { return Document::getList($whereClause); } } ?>