Commit bf8f7fb723625a3f15459805bbe8568fe80921c6

Authored by Paul Barrett
1 parent fb7f6cc4

CMIS: Added support for return of failed objects when calling deleteTree

Story ID: 966932. In order to be able to delete content using a CMIS client, as a user, I would like KnowledgeTree's CMIS interface to support delete

Committed by: Paul Barrett
ktapi/KTAPIFolder.inc.php
... ... @@ -798,6 +798,294 @@ class KTAPI_Folder extends KTAPI_FolderItem
798 798  
799 799 return $contents;
800 800 }
  801 +
  802 + /**
  803 + * Get's a folder listing, recursing to the maximum depth.
  804 + * Derived from the get_listing function.
  805 + *
  806 + * <code>
  807 + * $root = $this->ktapi->get_root_folder();
  808 + * $listing = $root->get_full_listing();
  809 + * foreach($listing as $val) {
  810 + * if($val['item_type'] == 'F') {
  811 + * // It's a folder
  812 + * echo $val['title'];
  813 + * }
  814 + * }
  815 + * </code>
  816 + *
  817 + * @author KnowledgeTree Team
  818 + * @access public
  819 + * @param string $what
  820 + * @return array
  821 + */
  822 + function get_full_listing($what='DFS')
  823 + {
  824 + $what = strtoupper($what);
  825 + $read_permission = &KTPermission::getByName(KTAPI_PERMISSION_READ);
  826 + $folder_permission = &KTPermission::getByName(KTAPI_PERMISSION_VIEW_FOLDER);
  827 +
  828 + $config = KTConfig::getSingleton();
  829 +
  830 + $wsversion = $config->get('webservice/version', LATEST_WEBSERVICE_VERSION);
  831 +
  832 + $user = $this->ktapi->get_user();
  833 +
  834 + $contents = array();
  835 +
  836 + if (strpos($what,'F') !== false)
  837 + {
  838 +
  839 + $folder_children = Folder::getList(array('parent_id = ?', $this->folderid));
  840 +
  841 + foreach ($folder_children as $folder)
  842 + {
  843 + if(KTPermissionUtil::userHasPermissionOnItem($user, $folder_permission, $folder) ||
  844 + KTPermissionUtil::userHasPermissionOnItem($user, $read_permission, $folder))
  845 + {
  846 + $sub_folder = &$this->ktapi->get_folder_by_id($folder->getId());
  847 + if (!PEAR::isError($sub_folder))
  848 + {
  849 + $items = $sub_folder->get_full_listing($what);
  850 + }
  851 + else
  852 + {
  853 + $items = array();
  854 + }
  855 +
  856 + $creator = $this->_resolve_user($folder->getCreatorID());
  857 +
  858 +
  859 + if ($wsversion >= 2)
  860 + {
  861 + $array = array(
  862 + 'id' => (int) $folder->getId(),
  863 + 'item_type' => 'F',
  864 +
  865 + 'custom_document_no'=>'n/a',
  866 + 'oem_document_no'=>'n/a',
  867 +
  868 + 'title' => $folder->getName(),
  869 + 'document_type' => 'n/a',
  870 + 'filename' => $folder->getName(),
  871 + 'filesize' => 'n/a',
  872 +
  873 + 'created_by' => is_null($creator)?'n/a':$creator->getName(),
  874 + 'created_date' => 'n/a',
  875 +
  876 + 'checked_out_by' => 'n/a',
  877 + 'checked_out_date' => 'n/a',
  878 +
  879 + 'modified_by' => 'n/a',
  880 + 'modified_date' => 'n/a',
  881 +
  882 + 'owned_by' => 'n/a',
  883 +
  884 + 'version' => 'n/a',
  885 +
  886 + 'is_immutable'=> 'n/a',
  887 + 'permissions' => KTAPI_Folder::get_permission_string($folder),
  888 +
  889 + 'workflow'=>'n/a',
  890 + 'workflow_state'=>'n/a',
  891 +
  892 + 'mime_type' => 'folder',
  893 + 'mime_icon_path' => 'folder',
  894 + 'mime_display' => 'Folder',
  895 +
  896 + 'storage_path' => 'n/a',
  897 + );
  898 +
  899 + if($wsversion>=3)
  900 + {
  901 + $array['linked_folder_id'] = $folder->getLinkedFolderId();
  902 + if($folder->isSymbolicLink()) {
  903 + $array['item_type'] = "S";
  904 + }
  905 + }
  906 +
  907 + $array['items']=$items;
  908 + if($wsversion<3 || (strpos($what,'F') !== false && !$folder->isSymbolicLink()) ||
  909 + ($folder->isSymbolicLink() && strpos($what,'S') !== false)) {
  910 + $contents[] = $array;
  911 + }
  912 + }
  913 + else
  914 + {
  915 + $contents[] = array(
  916 + 'id' => (int) $folder->getId(),
  917 + 'item_type'=>'F',
  918 + 'title'=>$folder->getName(),
  919 + 'creator'=>is_null($creator)?'n/a':$creator->getName(),
  920 + 'checkedoutby'=>'n/a',
  921 + 'modifiedby'=>'n/a',
  922 + 'filename'=>$folder->getName(),
  923 + 'size'=>'n/a',
  924 + 'major_version'=>'n/a',
  925 + 'minor_version'=>'n/a',
  926 + 'storage_path'=>'n/a',
  927 + 'mime_type'=>'folder',
  928 + 'mime_icon_path'=>'folder',
  929 + 'mime_display'=>'Folder',
  930 + 'items'=>$items,
  931 + 'workflow'=>'n/a',
  932 + 'workflow_state'=>'n/a'
  933 + );
  934 + }
  935 +
  936 + }
  937 + }
  938 +
  939 + }
  940 +
  941 + if (strpos($what,'D') !== false)
  942 + {
  943 + $document_children = Document::getList(array('folder_id = ? AND status_id = 1', $this->folderid));
  944 +
  945 + // I hate that KT doesn't cache things nicely...
  946 + $mime_cache = array();
  947 +
  948 + foreach ($document_children as $document)
  949 + {
  950 + if (KTPermissionUtil::userHasPermissionOnItem($user, $read_permission, $document))
  951 + {
  952 + $created_by=$this->_resolve_user($document->getCreatorID());
  953 + $created_date = $document->getCreatedDateTime();
  954 + if (empty($created_date)) $created_date = 'n/a';
  955 +
  956 + $checked_out_by=$this->_resolve_user($document->getCheckedOutUserID());
  957 + $checked_out_date = $document->getCheckedOutDate();
  958 + if (empty($checked_out_date)) $checked_out_date = 'n/a';
  959 +
  960 + $modified_by=$this->_resolve_user($document->getCreatorID());
  961 + $modified_date = $document->getLastModifiedDate();
  962 + if (empty($modified_date)) $modified_date = 'n/a';
  963 +
  964 + $owned_by =$this->_resolve_user($document->getOwnerID());
  965 +
  966 + $mimetypeid=$document->getMimeTypeID();
  967 + if (!array_key_exists($mimetypeid, $mime_cache))
  968 + {
  969 +
  970 + $type=KTMime::getMimeTypeName($mimetypeid);
  971 + $icon=KTMime::getIconPath($mimetypeid);
  972 + $display=KTMime::getFriendlyNameForString($type);
  973 + $mime_cache[$mimetypeid] = array(
  974 + 'type'=>$type,
  975 + 'icon'=>$icon,
  976 + 'display'=>$display
  977 +
  978 + );
  979 + }
  980 + $mimeinfo=$mime_cache[$mimetypeid];
  981 +
  982 + $workflow='n/a';
  983 + $state='n/a';
  984 +
  985 + $wf = KTWorkflowUtil::getWorkflowForDocument($document);
  986 +
  987 + if (!is_null($wf) && !PEAR::isError($wf))
  988 + {
  989 + $workflow=$wf->getHumanName();
  990 +
  991 + $ws=KTWorkflowUtil::getWorkflowStateForDocument($document);
  992 + if (!is_null($ws) && !PEAR::isError($ws))
  993 + {
  994 + $state=$ws->getHumanName();
  995 + }
  996 + }
  997 +
  998 + if ($wsversion >= 2)
  999 + {
  1000 + $docTypeId = $document->getDocumentTypeID();
  1001 + $documentType = DocumentType::get($docTypeId);
  1002 +
  1003 + $oemDocumentNo = $document->getOemNo();
  1004 + if (empty($oemDocumentNo)) $oemDocumentNo = 'n/a';
  1005 +
  1006 +
  1007 + $array = array(
  1008 + 'id' => (int) $document->getId(),
  1009 + 'item_type' => 'D',
  1010 +
  1011 + 'custom_document_no'=>'n/a',
  1012 + 'oem_document_no'=>$oemDocumentNo,
  1013 +
  1014 + 'title' => $document->getName(),
  1015 + 'document_type'=>$documentType->getName(),
  1016 + 'filename' => $document->getFileName(),
  1017 + 'filesize' => $document->getFileSize(),
  1018 +
  1019 + 'created_by' => is_null($created_by)?'n/a':$created_by->getName(),
  1020 + 'created_date' => $created_date,
  1021 +
  1022 + 'checked_out_by' => is_null($checked_out_by)?'n/a':$checked_out_by->getName(),
  1023 + 'checked_out_date' => $checked_out_date,
  1024 +
  1025 + 'modified_by' => is_null($modified_by)?'n/a':$modified_by->getName(),
  1026 + 'modified_date' => $modified_date,
  1027 +
  1028 + 'owned_by' => is_null($owned_by)?'n/a':$owned_by->getName(),
  1029 +
  1030 + 'version' => $document->getMajorVersionNumber() . '.' . $document->getMinorVersionNumber(),
  1031 + 'content_id' => $document->getContentVersionId(),
  1032 +
  1033 + 'is_immutable'=> $document->getImmutable()?'true':'false',
  1034 + 'permissions' => KTAPI_Document::get_permission_string($document),
  1035 +
  1036 + 'workflow'=> $workflow,
  1037 + 'workflow_state'=> $state,
  1038 +
  1039 + 'mime_type' => $mime_cache[$mimetypeid]['type'],
  1040 + 'mime_icon_path' => $mime_cache[$mimetypeid]['icon'],
  1041 + 'mime_display' => $mime_cache[$mimetypeid]['display'],
  1042 +
  1043 + 'storage_path' => $document->getStoragePath(),
  1044 + );
  1045 + if($wsversion>=3){
  1046 + $document->switchToRealCore();
  1047 + $array['linked_document_id'] = $document->getLinkedDocumentId();
  1048 + $document->switchToLinkedCore();
  1049 + if($document->isSymbolicLink()){
  1050 + $array['item_type'] = "S";
  1051 + }
  1052 + }
  1053 +
  1054 + $array['items']=array();
  1055 +
  1056 +
  1057 + if($wsversion<3 || (strpos($what,'D') !== false && !$document->isSymbolicLink()) || ($document->isSymbolicLink() && strpos($what,'S') !== false)){
  1058 + $contents[] = $array;
  1059 + }
  1060 + }
  1061 + else
  1062 + {
  1063 + $contents[] = array(
  1064 + 'id' => (int) $document->getId(),
  1065 + 'item_type'=>'D',
  1066 + 'title'=>$document->getName(),
  1067 + 'creator'=>is_null($created_by)?'n/a':$created_by->getName(),
  1068 + 'checkedoutby'=>is_null($checked_out_by)?'n/a':$checked_out_by->getName(),
  1069 + 'modifiedby'=>is_null($modified_by)?'n/a':$modified_by->getName(),
  1070 + 'filename'=>$document->getFileName(),
  1071 + 'size'=>$document->getFileSize(),
  1072 + 'major_version'=>$document->getMajorVersionNumber(),
  1073 + 'minor_version'=>$document->getMinorVersionNumber(),
  1074 + 'storage_path'=>$document->getStoragePath(),
  1075 + 'mime_type'=>$mime_cache[$mimetypeid]['type'],
  1076 + 'mime_icon_path'=>$mime_cache[$mimetypeid]['icon'],
  1077 + 'mime_display'=>$mime_cache[$mimetypeid]['display'],
  1078 + 'items'=>array(),
  1079 + 'workflow'=>$workflow,
  1080 + 'workflow_state'=>$state
  1081 + );
  1082 + }
  1083 + }
  1084 + }
  1085 + }
  1086 +
  1087 + return $contents;
  1088 + }
801 1089  
802 1090 /**
803 1091 * This adds a shortcut to an existing document to the current folder
... ...
lib/api/ktcmis/ktcmis.inc.php
... ... @@ -633,6 +633,15 @@ class KTObjectService extends KTCMISBase {
633 633 );
634 634 }
635 635  
  636 + // check whether there is a list of items which did not delete
  637 + if (count($result) > 0)
  638 + {
  639 + return array(
  640 + "status_code" => 1,
  641 + "message" => $result
  642 + );
  643 + }
  644 +
636 645 return array(
637 646 'status_code' => 0,
638 647 'results' => $objectId
... ...
lib/api/ktcmis/services/CMISObjectService.inc.php
... ... @@ -535,8 +535,25 @@ class CMISObjectService {
535 535 // TODO list of objects which failed in $failedToDelete array;
536 536 // since we do not delete the folder or any contents if anything cannot be deleted, this will contain the entire tree listing
537 537 // NOTE once we do this we will need to deal with it externally as well, since we can no longer just catch an exception.
538   - if ($result['status_code'] == 1) {
539   - throw new RuntimeException('There was an error deleting the object: ' . $result['message']);
  538 + if ($result['status_code'] == 1)
  539 + {
  540 + // TODO consider sending back full properties on each object?
  541 + // Not sure yet what this output may be used for by a client, and the current specification (0.61c) says:
  542 + // "A list of identifiers of objects in the folder tree that were not deleted", so let's leave it returning just ids for now.
  543 + $failedToDelete[] = CMISUtil::encodeObjectId('Folder', $objectId);
  544 + $folderContents = $object->get_full_listing();
  545 + foreach($folderContents as $folderObject)
  546 + {
  547 + if ($folderObject['item_type'] == 'F') $type = 'Folder';
  548 + else if ($folderObject['item_type'] == 'D') $type = 'Document';
  549 + // TODO deal with non-folder and non-document content
  550 + else continue;
  551 +
  552 + // TODO find out whether this is meant to be a hierarchical list or simply a list.
  553 + // for now we are just returning the list in non-hierarchical form
  554 + // (seeing as we don't really know how CMIS AtomPub is planning to deal with hierarchies at this time.)
  555 + $failedToDelete[] = CMISUtil::encodeObjectId($type, $folderObject['id']);
  556 + }
540 557 }
541 558  
542 559 return $failedToDelete;
... ...
webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php
... ... @@ -177,9 +177,34 @@ class KT_cmis_atom_service_folder extends KT_atom_service {
177 177 $this->responseFeed = $feed;
178 178 return null;
179 179 }
  180 + // list of failed objects?
  181 + if (is_array($result))
  182 + {
  183 + $this->setStatus(self::STATUS_SERVER_ERROR);
  184 +
  185 + $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
  186 + $feed->newField('title', 'Error: Failed to delete all objects in tree: ' . self::STATUS_SERVER_ERROR, $feed);
  187 +
  188 + foreach($result as $failed)
  189 + {
  190 + $entry = $feed->newEntry();
  191 + $objectElement = $feed->newElement('cmis:object');
  192 + $propertiesElement = $feed->newElement('cmis:properties');
  193 + $propElement = $feed->newElement('cmis:propertyId');
  194 + $propElement->appendChild($feed->newAttr('cmis:name', 'ObjectId'));
  195 + $feed->newField('cmis:value', $failed, $propElement);
  196 + $propertiesElement->appendChild($propElement);
  197 + $objectElement->appendChild($propertiesElement);
  198 + $entry->appendChild($objectElement);
  199 + $entry->appendChild($feed->newElement('cmis:terminator'));
  200 + }
  201 +
  202 + $this->responseFeed = $feed;
  203 + return null;
  204 + }
180 205  
181 206 // success
182   - $this->setStatus(self::STATUS_NO_CONTENT);
  207 + $this->setStatus(self::STATUS_NO_CONTENT);
183 208 }
184 209  
185 210 /**
... ...
webservice/classes/atompub/cmis/ObjectService.inc.php
... ... @@ -119,6 +119,9 @@ class ObjectService extends KTObjectService {
119 119 if ($result['status_code'] == 0) {
120 120 return $result['results'];
121 121 }
  122 + else if (is_array($result['message'])) {
  123 + return $result['message'];
  124 + }
122 125 else {
123 126 return new PEAR_Error($result['message']);
124 127 }
... ...