diff --git a/lib/documentmanagement/Document.inc b/lib/documentmanagement/Document.inc index b073eb9..0e6c532 100644 --- a/lib/documentmanagement/Document.inc +++ b/lib/documentmanagement/Document.inc @@ -34,6 +34,7 @@ DEFINE("PUBLISHED", 2); DEFINE("DELETED", 3); DEFINE("ARCHIVED", 4); DEFINE("STATUS_INCOMPLETE", 5); +DEFINE("VERSION_DELETED", 6); require_once(KT_LIB_DIR . "/foldermanagement/Folder.inc"); require_once(KT_LIB_DIR . '/documentmanagement/documentcontentversion.inc.php'); @@ -115,6 +116,9 @@ class Document { function getStatusID() { return $this->_oDocumentCore->getStatusId(); } function setStatusID($iNewValue) { $this->_oDocumentMetadataVersion->setStatusId($iNewValue); $this->_oDocumentCore->setStatusId($iNewValue); } + function getMetadataStatusID() { return $this->_oDocumentMetadataVersion->getStatusId(); } + function setMetadataStatusID($iNewValue) { $this->_oDocumentMetadataVersion->setStatusId($iNewValue); } + function getMetadataVersion() { return $this->_oDocumentMetadataVersion->getMetadataVersion(); } function setMetadataVersion($iNewValue) { $this->_oDocumentMetadataVersion->getMetadataVersion($iNewValue); } diff --git a/lib/documentmanagement/PhysicalDocumentManager.inc b/lib/documentmanagement/PhysicalDocumentManager.inc index f8b5f50..846a883 100644 --- a/lib/documentmanagement/PhysicalDocumentManager.inc +++ b/lib/documentmanagement/PhysicalDocumentManager.inc @@ -284,6 +284,36 @@ class PhysicalDocumentManager { } } + /** + * Delete a single version of a document + * + * return boolean true on successful delete, false otherwise + */ + function deleteVersion($oVersion) { + global $default; + $iContentId = $oVersion->getContentVersionId(); + $oContentVersion = KTDocumentContentVersion::get($iContentId); + + $sFullPath = $default->documentRoot.'/'.$oContentVersion->getStoragePath(); + + if (file_exists($sFullPath)) { + if(@unlink($sFullPath)){ + $default->log->info("PhysicalDocumentManager::deleteVersion unlinked $sFullPath"); + return true; + }else{ + $default->log->info("PhysicalDocumentManager::deleteVersion couldn't unlink $sFullPath"); + if (file_exists($sFullPath)) { + return false; + } else { + return true; + } + } + }else{ + $default->log->info("PhysicalDocumentManager::deleteVersion can't rm $sFullPath because it doesn't exist"); + return true; + } + } + /** * Restore a document from the Deleted/ folder to the specified folder * diff --git a/lib/documentmanagement/documentutil.inc.php b/lib/documentmanagement/documentutil.inc.php index 3922bfc..493977d 100644 --- a/lib/documentmanagement/documentutil.inc.php +++ b/lib/documentmanagement/documentutil.inc.php @@ -1013,7 +1013,67 @@ class KTDocumentUtil { return KTPermissionUtil::updatePermissionLookup($oDocument); } + + /** + * Delete a selected version of the document. + */ + function deleteVersion($oDocument, $iVersionID, $sReason){ + + $oDocument =& KTUtil::getObject('Document', $oDocument); + $oVersion =& KTDocumentMetadataVersion::get($iVersionID); + + $oStorageManager =& KTStorageManagerUtil::getSingleton(); + + global $default; + + if (empty($sReason)) { + return PEAR::raiseError(_kt('Deletion requires a reason')); + } + + if (PEAR::isError($oDocument) || ($oDocument == false)) { + return PEAR::raiseError(_kt('Invalid document object.')); + } + + if (PEAR::isError($oVersion) || ($oVersion == false)) { + return PEAR::raiseError(_kt('Invalid document version object.')); + } + + $iContentId = $oVersion->getContentVersionId(); + $oContentVersion = KTDocumentContentVersion::get($iContentId); + + if (PEAR::isError($oContentVersion) || ($oContentVersion == false)) { + DBUtil::rollback(); + return PEAR::raiseError(_kt('Invalid document content version object.')); + } + DBUtil::startTransaction(); + + // now delete the document version + $res = $oStorageManager->deleteVersion($oVersion); + if (PEAR::isError($res) || ($res == false)) { + //could not delete the document version from the file system + $default->log->error('Deletion: Filesystem error deleting the metadata version ' . + $oVersion->getMetadataVersion() . ' of the document ' . + $oDocument->getFileName() . ' from folder ' . + Folder::getFolderPath($oDocument->getFolderID()) . + ' id=' . $oDocument->getFolderID()); + + // we use a _real_ transaction here ... + + DBUtil::rollback(); + + return PEAR::raiseError(_kt('There was a problem deleting the document from storage.')); + } + + // change status for the metadata version + $oVersion->setStatusId(VERSION_DELETED); + $oVersion->update(); + + // set the storage path to empty +// $oContentVersion->setStoragePath(''); + + DBUtil::commit(); + } } class KTMetadataValidationError extends PEAR_Error { diff --git a/lib/storage/ondiskhashedstoragemanager.inc.php b/lib/storage/ondiskhashedstoragemanager.inc.php index dbb2742..bff30cc 100644 --- a/lib/storage/ondiskhashedstoragemanager.inc.php +++ b/lib/storage/ondiskhashedstoragemanager.inc.php @@ -302,6 +302,25 @@ class KTOnDiskHashedStorageManager extends KTStorageManager { return true; } + /** + * Completely remove a document version + * + * return boolean true on successful delete + */ + function deleteVersion($oVersion) { + $oConfig =& KTConfig::getSingleton(); + $sDocumentRoot = $oConfig->get('urls/documentRoot'); + $iContentId = $oVersion->getContentVersionId(); + $oContentVersion = KTDocumentContentVersion::get($iContentId); + + $sPath = $oContentVersion->getStoragePath(); + $sFullPath = sprintf("%s/%s", $sDocumentRoot, $sPath); + if (file_exists($sFullPath)) { + unlink($sFullPath); + } + return true; + } + function restore($oDocument) { // Storage doesn't care if the document is deleted or restored return true; diff --git a/lib/storage/ondiskpathstoragemanager.inc.php b/lib/storage/ondiskpathstoragemanager.inc.php index 97e9b84..6b81d21 100644 --- a/lib/storage/ondiskpathstoragemanager.inc.php +++ b/lib/storage/ondiskpathstoragemanager.inc.php @@ -399,6 +399,25 @@ class KTOnDiskPathStorageManager extends KTStorageManager { } return true; } + + /** + * Completely remove a document version + * + * return boolean true on successful delete + */ + function deleteVersion($oVersion) { + $oConfig =& KTConfig::getSingleton(); + $sDocumentRoot = $oConfig->get('urls/documentRoot'); + $iContentId = $oVersion->getContentVersionId(); + $oContentVersion = KTDocumentContentVersion::get($iContentId); + + $sPath = $oContentVersion->getStoragePath(); + $sFullPath = sprintf("%s/%s", $sDocumentRoot, $sPath); + if (file_exists($sFullPath)) { + unlink($sFullPath); + } + return true; + } /** * Restore a document from the Deleted/ folder to the specified folder diff --git a/lib/storage/storagemanager.inc.php b/lib/storage/storagemanager.inc.php index 3cdda8e..19af3ec 100644 --- a/lib/storage/storagemanager.inc.php +++ b/lib/storage/storagemanager.inc.php @@ -125,6 +125,10 @@ class KTStorageManager { $indexer->deleteDocument($documentid); } + function deleteVersion(&$oVersion) { + return PEAR::raiseError(_kt("Not implemented")); + } + /** * Performs any storage changes necessary to account for the * document (previously marked as deleted) being restored. diff --git a/plugins/ktcore/KTDocumentActions.php b/plugins/ktcore/KTDocumentActions.php index 4be4635..86c7273 100644 --- a/plugins/ktcore/KTDocumentActions.php +++ b/plugins/ktcore/KTDocumentActions.php @@ -114,6 +114,8 @@ class KTDocumentVersionHistoryAction extends KTDocumentAction { } function do_main() { + $show_version = KTUtil::arrayGet($_REQUEST, 'show'); + $showall = (isset($show_version) && ($show_version == 'all')) ? true : false; $this->oPage->setSecondaryTitle($this->oDocument->getName()); $this->oPage->setBreadcrumbDetails(_kt('Version History')); @@ -121,7 +123,12 @@ class KTDocumentVersionHistoryAction extends KTDocumentAction { $aMetadataVersions = KTDocumentMetadataVersion::getByDocument($this->oDocument); $aVersions = array(); foreach ($aMetadataVersions as $oVersion) { - $aVersions[] = Document::get($this->oDocument->getId(), $oVersion->getId()); + $version = Document::get($this->oDocument->getId(), $oVersion->getId()); + if($showall){ + $aVersions[] = $version; + }else if($version->getMetadataStatusID() != VERSION_DELETED){ + $aVersions[] = $version; + } } // render pass. @@ -134,12 +141,24 @@ class KTDocumentVersionHistoryAction extends KTDocumentAction { $oAction->setDocument($this->oDocument); + // create delete action if user is sys admin or folder admin + $bShowDelete = false; + require_once(KT_LIB_DIR . '/security/Permission.inc'); + $oUser =& User::get($_SESSION['userID']); + $iFolderId = $this->oDocument->getFolderId(); + if (Permission::userIsSystemAdministrator($oUser) || Permission::isUnitAdministratorForFolder($oUser, $iFolderId)) { + // Check if admin mode is enabled + $bShowDelete = KTUtil::arrayGet($_SESSION, 'adminmode', false); + } + $aTemplateData = array( 'context' => $this, 'document_id' => $this->oDocument->getId(), 'document' => $this->oDocument, 'versions' => $aVersions, 'downloadaction' => $oAction, + 'showdelete' => $bShowDelete, + 'showall' => $showall, ); return $oTemplate->render($aTemplateData); } @@ -195,12 +214,50 @@ class KTDocumentVersionHistoryAction extends KTDocumentAction { redirect(KTUtil::ktLink('view.php',null,implode('&', $frag))); } - function getUserForId($iUserId) { $u = User::get($iUserId); if (PEAR::isError($u) || ($u == false)) { return _kt('User no longer exists'); } return $u->getName(); } + + function do_confirmdeleteVersion() { + $this->oPage->setSecondaryTitle($this->oDocument->getName()); + $this->oPage->setBreadcrumbDetails(_kt('Delete document version')); + + // Display the version name and number + $iVersionId = $_REQUEST['version']; + $oVersion = Document::get($this->oDocument->getId(), $iVersionId); + + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('ktcore/document/delete_version'); + $aTemplateData = array( + 'context' => $this, + 'fDocumentId' => $this->oDocument->getId(), + 'oVersion' => $oVersion, + ); + return $oTemplate->render($aTemplateData); + } + + function do_deleteVersion() { + $iVersionId = $_REQUEST['versionid']; + $sReason = $_REQUEST['reason']; + $oVersion = Document::get($this->oDocument->getId(), $iVersionId); + + $res = KTDocumentUtil::deleteVersion($this->oDocument, $iVersionId, $sReason); + + if(PEAR::isError($res)){ + $this->addErrorMessage($res->getMessage()); + redirect(KTDocumentAction::getURL()); + exit(0); + } + + // Record the transaction + $aOptions['version'] = sprintf('%d.%d', $oVersion->getMajorVersionNumber(), $oVersion->getMinorVersionNumber()); + $oDocumentTransaction = & new DocumentTransaction($this->oDocument, _kt('Document version deleted'), 'ktcore.transactions.delete_version', $aOptions); + $oDocumentTransaction->create(); + + redirect(KTDocumentAction::getURL()); + } } // }}} @@ -225,7 +282,7 @@ class KTDocumentViewAction extends KTDocumentAction { $iVersion = KTUtil::arrayGet($_REQUEST, 'version'); if ($iVersion) { $oVersion = KTDocumentContentVersion::get($iVersion); - $aOptions['version'] = sprintf('%d.%d', $oVersion->getMajorVersionNumber(), $oVersion->getMinorVersionNumber());; + $aOptions['version'] = sprintf('%d.%d', $oVersion->getMajorVersionNumber(), $oVersion->getMinorVersionNumber()); $res = $oStorage->downloadVersion($this->oDocument, $iVersion); } else { $res = $oStorage->download($this->oDocument); diff --git a/sql/mysql/install/data.sql b/sql/mysql/install/data.sql index a6ac62e..df9f008 100644 --- a/sql/mysql/install/data.sql +++ b/sql/mysql/install/data.sql @@ -279,7 +279,7 @@ UNLOCK TABLES; LOCK TABLES `document_transaction_types_lookup` WRITE; /*!40000 ALTER TABLE `document_transaction_types_lookup` DISABLE KEYS */; -INSERT INTO `document_transaction_types_lookup` VALUES (1,'Create','ktcore.transactions.create'),(2,'Update','ktcore.transactions.update'),(3,'Delete','ktcore.transactions.delete'),(4,'Rename','ktcore.transactions.rename'),(5,'Move','ktcore.transactions.move'),(6,'Download','ktcore.transactions.download'),(7,'Check In','ktcore.transactions.check_in'),(8,'Check Out','ktcore.transactions.check_out'),(9,'Collaboration Step Rollback','ktcore.transactions.collaboration_step_rollback'),(10,'View','ktcore.transactions.view'),(11,'Expunge','ktcore.transactions.expunge'),(12,'Force CheckIn','ktcore.transactions.force_checkin'),(13,'Email Link','ktcore.transactions.email_link'),(14,'Collaboration Step Approve','ktcore.transactions.collaboration_step_approve'),(15,'Email Attachment','ktcore.transactions.email_attachment'),(16,'Workflow state transition','ktcore.transactions.workflow_state_transition'),(17,'Permissions changed','ktcore.transactions.permissions_change'),(18,'Role allocations changed','ktcore.transactions.role_allocations_change'),(19,'Bulk Export','ktstandard.transactions.bulk_export'),(20,'Copy','ktcore.transactions.copy'); +INSERT INTO `document_transaction_types_lookup` VALUES (1,'Create','ktcore.transactions.create'),(2,'Update','ktcore.transactions.update'),(3,'Delete','ktcore.transactions.delete'),(4,'Rename','ktcore.transactions.rename'),(5,'Move','ktcore.transactions.move'),(6,'Download','ktcore.transactions.download'),(7,'Check In','ktcore.transactions.check_in'),(8,'Check Out','ktcore.transactions.check_out'),(9,'Collaboration Step Rollback','ktcore.transactions.collaboration_step_rollback'),(10,'View','ktcore.transactions.view'),(11,'Expunge','ktcore.transactions.expunge'),(12,'Force CheckIn','ktcore.transactions.force_checkin'),(13,'Email Link','ktcore.transactions.email_link'),(14,'Collaboration Step Approve','ktcore.transactions.collaboration_step_approve'),(15,'Email Attachment','ktcore.transactions.email_attachment'),(16,'Workflow state transition','ktcore.transactions.workflow_state_transition'),(17,'Permissions changed','ktcore.transactions.permissions_change'),(18,'Role allocations changed','ktcore.transactions.role_allocations_change'),(19,'Bulk Export','ktstandard.transactions.bulk_export'),(20,'Copy','ktcore.transactions.copy'),(21,'Delete Version','ktcore.transactions.delete_version'); /*!40000 ALTER TABLE `document_transaction_types_lookup` ENABLE KEYS */; UNLOCK TABLES; @@ -786,7 +786,7 @@ UNLOCK TABLES; LOCK TABLES `status_lookup` WRITE; /*!40000 ALTER TABLE `status_lookup` DISABLE KEYS */; -INSERT INTO `status_lookup` VALUES (1,'Live'),(2,'Published'),(3,'Deleted'),(4,'Archived'),(5,'Incomplete'); +INSERT INTO `status_lookup` VALUES (1,'Live'),(2,'Published'),(3,'Deleted'),(4,'Archived'),(5,'Incomplete'),(6,'Version Deleted'); /*!40000 ALTER TABLE `status_lookup` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/mysql/upgrade/3.5.0/document_transaction_type.sql b/sql/mysql/upgrade/3.5.0/document_transaction_type.sql new file mode 100644 index 0000000..6c27b1d --- /dev/null +++ b/sql/mysql/upgrade/3.5.0/document_transaction_type.sql @@ -0,0 +1,2 @@ +INSERT INTO `document_transaction_types_lookup` VALUES (21,'Delete Version','ktcore.transactions.delete_version'); +INSERT INTO `status_lookup` VALUES (6,'Version Deleted'); \ No newline at end of file diff --git a/templates/ktcore/document/delete_version.smarty b/templates/ktcore/document/delete_version.smarty new file mode 100644 index 0000000..bb77084 --- /dev/null +++ b/templates/ktcore/document/delete_version.smarty @@ -0,0 +1,26 @@ +

{i18n}Delete Document Version{/i18n}

+ +{i18n}On deleting a document version the version history will remain but the document will be permanently deleted.{/i18n} +

{i18n}The following document version has been selected for deletion:{/i18n}

+ + + + + + + + + + +
Document Version: {$oVersion->getName()}
Metadata version: {$oVersion->getMetadataVersion()}
Content version: {$oVersion->getMajorVersionNumber()}.{$oVersion->getMinorVersionNumber()}
Date created: {$oVersion->getVersionCreated()}
+ +

+

+ + + +Reason: +
+
+
+

\ No newline at end of file diff --git a/templates/ktcore/document/metadata_history.smarty b/templates/ktcore/document/metadata_history.smarty index 43e3d32..7d029a9 100644 --- a/templates/ktcore/document/metadata_history.smarty +++ b/templates/ktcore/document/metadata_history.smarty @@ -13,6 +13,9 @@ {i18n}Compare with Current{/i18n} {i18n}Compare with Other Version{/i18n} {i18n}Date Created{/i18n} + {if $showdelete} + {i18n}Delete Version{/i18n} + {/if} @@ -22,24 +25,57 @@ {$oVersion->getMetadataVersion()} {capture assign=version}{$oVersion->getMajorVersionNumber()}.{$oVersion->getMinorVersionNumber()}{/capture} {capture assign=versionid}{$oVersion->getContentVersionId()}{/capture} - {$version} + + {if ($oVersion->getMetadataStatusID() != VERSION_DELETED)} + {$version} + {else} + {$version} + {/if} + {if ($document->getMetadataVersion() == $oVersion->getMetadataVersion())} {i18n}current version{/i18n} {else} - {i18n}compare with current{/i18n} + {if ($oVersion->getMetadataStatusID() != VERSION_DELETED)} + {i18n}compare with current{/i18n} + {else} + — + {/if} {/if} {if (count($versions) == 1)} — {else} - {i18n}compare with other version{/i18n} + {if ($oVersion->getMetadataStatusID() != VERSION_DELETED)} + {i18n}compare with other version{/i18n} + {else} + — + {/if} {/if} {$oVersion->getVersionCreated()} + {if $showdelete} + + {if ($document->getMetadataVersion() != $oVersion->getMetadataVersion())} + {if ($oVersion->getMetadataStatusID() == VERSION_DELETED)} + {i18n}Version deleted{/i18n} + {else} + {i18n}delete version{/i18n} + {/if} + {else} +   + {/if} + + {/if} {/foreach} + +{if ($showdelete && !$showall)} +

+ {i18n}Show deleted versions{/i18n} +

+{/if} \ No newline at end of file