Commit 81077932f738f57878511eea6542b449e87a0709

Authored by Paul Barrett
1 parent 6c79e197

KTS-4186. Prevented checked out documents from being deleted or archived by bulk…

… action.  I also added the folder checking code from the bulk move action to check into subfolders and prevent these actions when any document in the selected folder tree does not permit them.  Additionally I added this folder checking to the copy function since it made sense that it belongs in all 4 of the delete/move/copy/archive actions to check down into the folder structure before proceeding.

Checked out documents can be deleted or archived by bulk action

Fixed

Committed By: Paul Barrett

Reviewed by: Megan Watson
lib/documentmanagement/documentutil.inc.php
... ... @@ -1076,20 +1076,62 @@ $sourceDocument->getName(),
1076 1076 Indexer::index($oDocument);
1077 1077 }
1078 1078  
  1079 + function canBeCopied($oDocument, &$sError) {
  1080 + if ($oDocument->getIsCheckedOut()) {
  1081 + $sError = PEAR::raiseError(_kt('Document cannot be copied as it is checked out.'));
  1082 + return false;
  1083 + }
  1084 + if (!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.copy')) {
  1085 + $sError = PEAR::raiseError(_kt('Document cannot be copied as it is restricted by the workflow.'));
  1086 + return false;
  1087 + }
  1088 + return true;
  1089 + }
1079 1090  
1080   - function canBeMoved($oDocument) {
  1091 + function canBeMoved($oDocument, &$sError) {
  1092 + if ($oDocument->getImmutable()) {
  1093 + $sError = PEAR::raiseError(_kt('Document cannot be moved as it is immutable.'));
  1094 + return false;
  1095 + }
1081 1096 if ($oDocument->getIsCheckedOut()) {
  1097 + $sError = PEAR::raiseError(_kt('Document cannot be moved as it is checked out.'));
1082 1098 return false;
1083 1099 }
1084 1100 if (!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.move')) {
  1101 + $sError = PEAR::raiseError(_kt('Document cannot be moved as it is restricted by the workflow.'));
1085 1102 return false;
1086 1103 }
1087   - if ($oDocument->getImmutable()) {
  1104 + return true;
  1105 + }
  1106 +
  1107 + function canBeDeleted($oDocument, &$sError) {
  1108 + if($oDocument->getImmutable())
  1109 + {
  1110 + $sError = PEAR::raiseError(_kt('Document cannot be deleted as it is immutable.'));
  1111 + return false;
  1112 + }
  1113 + if ($oDocument->getIsCheckedOut()) {
  1114 + $sError = PEAR::raiseError(_kt('Document cannot be deleted as it is checked out.'));
  1115 + return false;
  1116 + }
  1117 + if(!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.delete')){
  1118 + $sError = PEAR::raiseError(_kt('Document cannot be deleted as it is restricted by the workflow.'));
1088 1119 return false;
1089 1120 }
1090 1121 return true;
1091 1122 }
1092 1123  
  1124 + function canBeArchived($oDocument, &$sError) {
  1125 + if ($oDocument->getIsCheckedOut()) {
  1126 + $sError = PEAR::raiseError(_kt('Document cannot be archived as it is checked out.'));
  1127 + return false;
  1128 + }
  1129 + if(!KTWorkflowUtil::actionEnabledForDocument($oDocument, 'ktcore.actions.document.archive')){
  1130 + $sError = PEAR::raiseError(_kt('Document cannot be archived as it is restricted by the workflow.'));
  1131 + return false;
  1132 + }
  1133 + return true;
  1134 + }
1093 1135  
1094 1136 function copy($oDocument, $oDestinationFolder, $sReason = null, $sDestinationDocName = null) {
1095 1137 // 1. generate a new triad of content, metadata and core objects.
... ...
plugins/ktcore/KTBulkActions.php
... ... @@ -53,14 +53,64 @@ class KTBulkDeleteAction extends KTBulkAction {
53 53  
54 54 function check_entity($oEntity) {
55 55 if(is_a($oEntity, 'Document')) {
56   - if($oEntity->getImmutable())
57   - {
58   - return PEAR::raiseError(_kt('Document cannot be deleted as it is immutable'));
  56 + if(!KTDocumentUtil::canBeDeleted($oEntity, $sError)) {
  57 + if (PEAR::isError($sError))
  58 + {
  59 + return $sError;
  60 + }
  61 + return PEAR::raiseError(_kt('Document cannot be deleted'));
59 62 }
60   - if(!KTWorkflowUtil::actionEnabledForDocument($oEntity, 'ktcore.actions.document.delete')){
61   - return PEAR::raiseError(_kt('Document cannot be deleted as it is restricted by the workflow.'));
  63 + }
  64 +
  65 + if(is_a($oEntity, 'Folder')) {
  66 + $aDocuments = array();
  67 + $aChildFolders = array();
  68 +
  69 + $oFolder = $oEntity;
  70 +
  71 + // Get folder id
  72 + $sFolderId = $oFolder->getID();
  73 +
  74 + // Get documents in folder
  75 + $sDocuments = $oFolder->getDocumentIDs($sFolderId);
  76 + $aDocuments = (!empty($sDocuments)) ? explode(',', $sDocuments) : array();
  77 +
  78 + // Loop through documents and send to this function for checking
  79 + if(!empty($aDocuments)){
  80 + foreach($aDocuments as $sDocID){
  81 + $oDocument = Document::get($sDocID);
  82 + $res = $this->check_entity($oDocument);
  83 + if (PEAR::isError($res))
  84 + {
  85 + // NOTE: we may want to append the document reason to this
  86 + // in order for the user to have some idea WHY the folder cannot be deleted
  87 + return PEAR::raiseError(_kt('Folder cannot be deleted'));
  88 + }
  89 + }
  90 + }
  91 +
  92 + // If all documents at the current level may be deleted, we can continue
  93 + // Get any existing subfolders
  94 + $sWhereClause = "parent_folder_ids = '{$sFolderId}' OR
  95 + parent_folder_ids LIKE '{$sFolderId},%' OR
  96 + parent_folder_ids LIKE '%,{$sFolderId},%' OR
  97 + parent_folder_ids LIKE '%,{$sFolderId}'";
  98 + $aChildFolders = $this->oFolder->getList($sWhereClause);
  99 +
  100 + // Loop through subfolders and check each in the same way as the parent
  101 + if(!empty($aChildFolders)){
  102 + foreach($aChildFolders as $oChild){
  103 + $res = $this->check_entity($oChild);
  104 + if (PEAR::isError($res))
  105 + {
  106 + // NOTE: we may want to append the document reason to this
  107 + // in order for the user to have some idea WHY the folder cannot be deleted
  108 + return PEAR::raiseError(_kt('Folder cannot be deleted'));
  109 + }
  110 + }
62 111 }
63 112 }
  113 +
64 114 return parent::check_entity($oEntity);
65 115 }
66 116  
... ... @@ -348,7 +398,11 @@ class KTBulkMoveAction extends KTBulkAction {
348 398 function check_entity($oEntity) {
349 399  
350 400 if(is_a($oEntity, 'Document')) {
351   - if(!KTDocumentUtil::canBeMoved($oEntity)) {
  401 + if(!KTDocumentUtil::canBeMoved($oEntity, $sError)) {
  402 + if (PEAR::isError($sError))
  403 + {
  404 + return $sError;
  405 + }
352 406 return PEAR::raiseError(_kt('Document cannot be moved'));
353 407 }
354 408 }
... ... @@ -373,6 +427,8 @@ class KTBulkMoveAction extends KTBulkAction {
373 427 $res = $this->check_entity($oDocument);
374 428 if (PEAR::isError($res))
375 429 {
  430 + // NOTE: we may want to append the document reason to this
  431 + // in order for the user to have some idea WHY the folder cannot be moved
376 432 return PEAR::raiseError(_kt('Folder cannot be moved'));
377 433 }
378 434 }
... ... @@ -392,6 +448,8 @@ class KTBulkMoveAction extends KTBulkAction {
392 448 $res = $this->check_entity($oChild);
393 449 if (PEAR::isError($res))
394 450 {
  451 + // NOTE: we may want to append the document reason to this
  452 + // in order for the user to have some idea WHY the folder cannot be moved
395 453 return PEAR::raiseError(_kt('Folder cannot be moved'));
396 454 }
397 455 }
... ... @@ -579,10 +637,64 @@ class KTBulkCopyAction extends KTBulkAction {
579 637  
580 638 function check_entity($oEntity) {
581 639 if(is_a($oEntity, 'Document')) {
582   - if(!KTDocumentUtil::canBeMoved($oEntity)) {
  640 + if(!KTDocumentUtil::canBeCopied($oEntity, $sError)) {
  641 + if (PEAR::isError($sError))
  642 + {
  643 + return $sError;
  644 + }
583 645 return PEAR::raiseError(_kt('Document cannot be copied'));
584 646 }
585 647 }
  648 +
  649 + if(is_a($oEntity, 'Folder')) {
  650 + $aDocuments = array();
  651 + $aChildFolders = array();
  652 +
  653 + $oFolder = $oEntity;
  654 +
  655 + // Get folder id
  656 + $sFolderId = $oFolder->getID();
  657 +
  658 + // Get documents in folder
  659 + $sDocuments = $oFolder->getDocumentIDs($sFolderId);
  660 + $aDocuments = (!empty($sDocuments)) ? explode(',', $sDocuments) : array();
  661 +
  662 + // Loop through documents and send to this function for checking
  663 + if(!empty($aDocuments)){
  664 + foreach($aDocuments as $sDocID){
  665 + $oDocument = Document::get($sDocID);
  666 + $res = $this->check_entity($oDocument);
  667 + if (PEAR::isError($res))
  668 + {
  669 + // NOTE: we may want to append the document reason to this
  670 + // in order for the user to have some idea WHY the folder cannot be copied
  671 + return PEAR::raiseError(_kt('Folder cannot be copied'));
  672 + }
  673 + }
  674 + }
  675 +
  676 + // If all documents at the current level may be copied, we can continue
  677 + // Get any existing subfolders
  678 + $sWhereClause = "parent_folder_ids = '{$sFolderId}' OR
  679 + parent_folder_ids LIKE '{$sFolderId},%' OR
  680 + parent_folder_ids LIKE '%,{$sFolderId},%' OR
  681 + parent_folder_ids LIKE '%,{$sFolderId}'";
  682 + $aChildFolders = $this->oFolder->getList($sWhereClause);
  683 +
  684 + // Loop through subfolders and check each in the same way as the parent
  685 + if(!empty($aChildFolders)){
  686 + foreach($aChildFolders as $oChild){
  687 + $res = $this->check_entity($oChild);
  688 + if (PEAR::isError($res))
  689 + {
  690 + // NOTE: we may want to append the document reason to this
  691 + // in order for the user to have some idea WHY the folder cannot be copied
  692 + return PEAR::raiseError(_kt('Folder cannot be copied'));
  693 + }
  694 + }
  695 + }
  696 + }
  697 +
586 698 return parent::check_entity($oEntity);
587 699 }
588 700  
... ... @@ -709,17 +821,76 @@ class KTBulkArchiveAction extends KTBulkAction {
709 821 }
710 822  
711 823 function check_entity($oEntity) {
  824 + // NOTE: these checks don't have an equivalent in the delete and move functions.
  825 + // possibly they are no longer needed but I am leaving them here
  826 + // to avoid any potential problems I may not be aware of
712 827 if((!is_a($oEntity, 'Document')) && (!is_a($oEntity, 'Folder'))) {
713   - return PEAR::raiseError(_kt('Document cannot be archived'));
  828 + return PEAR::raiseError(_kt('Document cannot be archived'));
714 829 }
  830 +
715 831 if($oEntity->isSymbolicLink()){
716 832 return PEAR::raiseError(_kt("It is not possible to archive a shortcut. Please archive the target document or folder instead."));
717 833 }
718   - if(is_a($oEntity, 'Document')){
719   - if(!KTWorkflowUtil::actionEnabledForDocument($oEntity, 'ktcore.actions.document.archive')){
720   - return PEAR::raiseError(_kt('Document cannot be archived as it is restricted by the workflow.'));
  834 +
  835 + if(is_a($oEntity, 'Document')) {
  836 + if(!KTDocumentUtil::canBeArchived($oEntity, $sError)) {
  837 + if (PEAR::isError($sError))
  838 + {
  839 + return $sError;
  840 + }
  841 + return PEAR::raiseError(_kt('Document cannot be archived'));
  842 + }
  843 + }
  844 +
  845 + if(is_a($oEntity, 'Folder')) {
  846 + $aDocuments = array();
  847 + $aChildFolders = array();
  848 +
  849 + $oFolder = $oEntity;
  850 +
  851 + // Get folder id
  852 + $sFolderId = $oFolder->getID();
  853 +
  854 + // Get documents in folder
  855 + $sDocuments = $oFolder->getDocumentIDs($sFolderId);
  856 + $aDocuments = (!empty($sDocuments)) ? explode(',', $sDocuments) : array();
  857 +
  858 + // Loop through documents and send to this function for checking
  859 + if(!empty($aDocuments)){
  860 + foreach($aDocuments as $sDocID){
  861 + $oDocument = Document::get($sDocID);
  862 + $res = $this->check_entity($oDocument);
  863 + if (PEAR::isError($res))
  864 + {
  865 + // NOTE: we may want to append the document reason to this
  866 + // in order for the user to have some idea WHY the folder cannot be archived
  867 + return PEAR::raiseError(_kt('Folder cannot be archived'));
  868 + }
  869 + }
  870 + }
  871 +
  872 + // If all documents at the current level may be archived, we can continue
  873 + // Get any existing subfolders
  874 + $sWhereClause = "parent_folder_ids = '{$sFolderId}' OR
  875 + parent_folder_ids LIKE '{$sFolderId},%' OR
  876 + parent_folder_ids LIKE '%,{$sFolderId},%' OR
  877 + parent_folder_ids LIKE '%,{$sFolderId}'";
  878 + $aChildFolders = $this->oFolder->getList($sWhereClause);
  879 +
  880 + // Loop through subfolders and check each in the same way as the parent
  881 + if(!empty($aChildFolders)){
  882 + foreach($aChildFolders as $oChild){
  883 + $res = $this->check_entity($oChild);
  884 + if (PEAR::isError($res))
  885 + {
  886 + // NOTE: we may want to append the document reason to this
  887 + // in order for the user to have some idea WHY the folder cannot be archived
  888 + return PEAR::raiseError(_kt('Folder cannot be archived'));
  889 + }
  890 + }
721 891 }
722 892 }
  893 +
723 894 return parent::check_entity($oEntity);
724 895 }
725 896  
... ... @@ -871,6 +1042,7 @@ class KTBulkArchiveAction extends KTBulkAction {
871 1042 }
872 1043 }
873 1044  
  1045 +// NOTE: None of the new code for folder recursion is implemented for this action.
874 1046 class KTBrowseBulkExportAction extends KTBulkAction {
875 1047 var $sName = 'ktcore.actions.bulk.export';
876 1048 var $_sPermission = 'ktcore.permissions.read';
... ... @@ -881,8 +1053,6 @@ class KTBrowseBulkExportAction extends KTBulkAction {
881 1053 return _kt('Download All');
882 1054 }
883 1055  
884   -
885   -
886 1056 function check_entity($oEntity) {
887 1057 if((!is_a($oEntity, 'Document')) && (!is_a($oEntity, 'Folder'))) {
888 1058 return PEAR::raiseError(_kt('Document cannot be exported'));
... ... @@ -1081,6 +1251,7 @@ class KTBrowseBulkExportAction extends KTBulkAction {
1081 1251 }
1082 1252 }
1083 1253  
  1254 +// NOTE: None of the new code for folder recursion is implemented for this action.
1084 1255 class KTBrowseBulkCheckoutAction extends KTBulkAction {
1085 1256 var $sName = 'ktcore.actions.bulk.checkout';
1086 1257 var $_sPermission = 'ktcore.permissions.write';
... ...