Commit bf8f7fb723625a3f15459805bbe8568fe80921c6
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
Showing
5 changed files
with
345 additions
and
3 deletions
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 | } | ... | ... |