Commit 07800ae62e89f829fe4ef2170376a29b4e55d27d
1 parent
fa3eed7c
AtomPub support for create folder and create document via CMIS API. internal se…
…rvice auth support via APACHE (note that auth will fail if PHP is run as a CGI module). Attempt to re-use sessions in ktcmis (untested). Committed by: Paul Barrett
Showing
12 changed files
with
273 additions
and
105 deletions
lib/api/ktcmis/config/repositories.xml
| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | <repositoryURI>http://127.0.0.1/</repositoryURI> |
| 14 | 14 | <repositoryInfo> |
| 15 | 15 | <repositoryId>0ad7de04-7914-41b1-b5ee-be9f0b626437</repositoryId> |
| 16 | - <repositoryName>KnowledgeTree</repositoryName> | |
| 16 | + <repositoryName>KnowledgeTree DMS</repositoryName> | |
| 17 | 17 | <repositoryRelationship>self</repositoryRelationship> |
| 18 | 18 | <repositoryDescription>KnowledgeTree Repository</repositoryDescription> |
| 19 | 19 | <vendorName>KnowledgeTree</vendorName> | ... | ... |
lib/api/ktcmis/ktcmis.inc.php
| ... | ... | @@ -70,18 +70,23 @@ class KTCMISBase { |
| 70 | 70 | // TODO try to pick up existing session if possible, i.e. if the $session value is not empty |
| 71 | 71 | public function startSession($username, $password) |
| 72 | 72 | { |
| 73 | - if (is_null(self::$session)) | |
| 73 | +// echo $username." :: ".$password."<BR>"; | |
| 74 | + // attempt to recover session if one exists | |
| 75 | + if (!is_null(self::$session) && !PEAR::isError(self::$session)) | |
| 74 | 76 | { |
| 75 | - self::$ktapi = new KTAPI(); | |
| 76 | - self::$session =& self::$ktapi->start_session($username, $password); | |
| 77 | +// echo "ATTEMPT TO RECOVER SESSION: ".print_r(self::$session, true)."<BR>\n"; | |
| 78 | + self::$session =& self::$ktapi->get_active_session(self::$session->get_sessionid()); | |
| 77 | 79 | } |
| 78 | - else | |
| 80 | + | |
| 81 | + // start new session if no existing session or problem getting existing session (expired, etc...) | |
| 82 | + if (is_null(self::$session) || PEAR::isError(self::$session)) | |
| 79 | 83 | { |
| 80 | - // add session restart code here | |
| 81 | - self::$session =& self::$ktapi->get_active_session(self::$session->get_sessionid()); | |
| 84 | +// echo "ATTEMPT TO START NEW SESSION<BR>\n"; | |
| 85 | + self::$ktapi = new KTAPI(); | |
| 86 | + self::$session =& self::$ktapi->start_session($username, $password); | |
| 82 | 87 | } |
| 83 | 88 | |
| 84 | - //var_dump(self::$ktapi); | |
| 89 | +// print_r(self::$ktapi); | |
| 85 | 90 | return self::$session; |
| 86 | 91 | } |
| 87 | 92 | |
| ... | ... | @@ -90,6 +95,11 @@ class KTCMISBase { |
| 90 | 95 | return self::$ktapi; |
| 91 | 96 | } |
| 92 | 97 | |
| 98 | + public function getSession() | |
| 99 | + { | |
| 100 | + return self::$session; | |
| 101 | + } | |
| 102 | + | |
| 93 | 103 | // TODO what about destroying sessions? only on logout (which is not offered by the CMIS clients tested so far) |
| 94 | 104 | } |
| 95 | 105 | ... | ... |
lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php
| ... | ... | @@ -110,6 +110,7 @@ class CMISDocumentObject extends CMISBaseObject { |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | 112 | $objectProperties = $object->get_detail(); |
| 113 | +// print_r($objectProperties); | |
| 113 | 114 | |
| 114 | 115 | $this->_setPropertyInternal('ObjectId', CMISUtil::encodeObjectId($this->typeId, $objectProperties['document_id'])); |
| 115 | 116 | // prevent doubled '/' chars |
| ... | ... | @@ -131,6 +132,7 @@ class CMISDocumentObject extends CMISBaseObject { |
| 131 | 132 | $this->_setPropertyInternal('LastModificationDate', $objectProperties['modified_date']); |
| 132 | 133 | $this->_setPropertyInternal('ChangeToken', null); |
| 133 | 134 | $this->_setPropertyInternal('Name', $objectProperties['title']); |
| 135 | + $this->_setPropertyInternal('ParentId', $objectProperties['folder_id']); | |
| 134 | 136 | $this->_setPropertyInternal('IsImmutable', $objectProperties['is_immutable']); |
| 135 | 137 | // NOTE if access to older versions is allowed, this will need to be checked, else just set to yes |
| 136 | 138 | // see ktapi::get_document_version_history | ... | ... |
lib/api/ktcmis/services/CMISObjectService.inc.php
| ... | ... | @@ -262,6 +262,12 @@ class CMISObjectService { |
| 262 | 262 | throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')'); |
| 263 | 263 | } |
| 264 | 264 | |
| 265 | + // TODO if name is blank! throw another exception (check type) - using RuntimeException for now | |
| 266 | + if (trim($properties['name']) == '') | |
| 267 | + { | |
| 268 | + throw new RuntimeException('Refusing to create an un-named folder'); | |
| 269 | + } | |
| 270 | + | |
| 265 | 271 | $response = $this->ktapi->create_folder((int)$folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = ''); |
| 266 | 272 | if ($response['status_code'] != 0) |
| 267 | 273 | { | ... | ... |
lib/api/ktcmis/util/CMISUtil.inc.php
| ... | ... | @@ -86,6 +86,12 @@ class CMISUtil { |
| 86 | 86 | */ |
| 87 | 87 | static public function decodeObjectId($objectId, &$typeId = null) |
| 88 | 88 | { |
| 89 | + if (!is_string($objectId)) | |
| 90 | + { | |
| 91 | + $typeId = 'Unknown'; | |
| 92 | + return null; | |
| 93 | + } | |
| 94 | + | |
| 89 | 95 | $typeId = null; |
| 90 | 96 | |
| 91 | 97 | preg_match('/(\D)(\d*)/', $objectId, $matches); |
| ... | ... | @@ -240,14 +246,11 @@ class CMISUtil { |
| 240 | 246 | 'value' => $properties->getValue('Name')); |
| 241 | 247 | $object['Author'] = array('value' => $properties->getValue('Author')); |
| 242 | 248 | |
| 243 | - if (strtolower($properties->getValue('ObjectTypeId')) == 'folder') | |
| 244 | - { | |
| 245 | - $object['properties']['ParentId'] = array('type' => $properties->getFieldType('ParentId'), | |
| 246 | - 'value' => CMISUtil::encodeObjectId('Folder', | |
| 247 | - $properties->getValue('ParentId'))); | |
| 248 | - } | |
| 249 | + $object['properties']['ParentId'] = array('type' => $properties->getFieldType('ParentId'), | |
| 250 | + 'value' => CMISUtil::encodeObjectId('Folder', | |
| 251 | + $properties->getValue('ParentId'))); | |
| 249 | 252 | // TODO should check for content stream data before filling these in |
| 250 | - else //if () | |
| 253 | + if (strtolower($properties->getValue('ObjectTypeId')) == 'document') | |
| 251 | 254 | { |
| 252 | 255 | $object['properties']['ContentStreamLength'] = array('type' => $properties->getFieldType('ContentStreamLength'), |
| 253 | 256 | 'value' => $properties->getValue('ContentStreamLength')); | ... | ... |
webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php
| ... | ... | @@ -17,14 +17,15 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service |
| 17 | 17 | { |
| 18 | 18 | public function GET_action() |
| 19 | 19 | { |
| 20 | - $username = $password = 'admin'; | |
| 21 | 20 | $RepositoryService = new RepositoryService(); |
| 22 | - $RepositoryService->startSession($username, $password); | |
| 21 | + $RepositoryService->startSession(self::$authData['username'], self::$authData['password']); | |
| 23 | 22 | $repositories = $RepositoryService->getRepositories(); |
| 24 | 23 | $repositoryId = $repositories[0]['repositoryId']; |
| 25 | -//var_dump($RepositoryService->ktapi); | |
| 26 | -// $folderId = $this->getFolderData(); | |
| 27 | 24 | |
| 25 | + // TODO implement full path/node separation as with Alfresco - i.e. path requests come in on path/ and node requests come in on node/ | |
| 26 | + // path request e.g.: Root Folder/DroppedDocuments | |
| 27 | + // node request e.g.: F1/children | |
| 28 | + // node request e.g.: F2 | |
| 28 | 29 | if (urldecode($this->params[0]) == 'Root Folder') |
| 29 | 30 | { |
| 30 | 31 | $folderId = CMISUtil::encodeObjectId('Folder', 1); |
| ... | ... | @@ -35,35 +36,28 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service |
| 35 | 36 | { |
| 36 | 37 | $ktapi =& $RepositoryService->getInterface(); |
| 37 | 38 | $folderId = KT_cmis_atom_service_helper::getFolderId($this->params, $ktapi); |
| 38 | -// echo "DA FOLDER ID IS $folderId<BR>"; | |
| 39 | 39 | } |
| 40 | 40 | else |
| 41 | 41 | { |
| 42 | 42 | $folderId = $this->params[0]; |
| 43 | -// // get folder name from id, using the ObjectService methods | |
| 44 | -// $ObjectService = new ObjectService(); | |
| 45 | -//// var_dump($ObjectService->ktapi); | |
| 46 | -// $ObjectService->setInterface(); | |
| 47 | -// $cmisProps = $ObjectService->getProperties($repositoryId, $folderId, false, false); | |
| 48 | -//// var_dump($cmisObject); | |
| 49 | -//// $props = $cmisObject->getProperties(); | |
| 50 | -//// var_dump($props); | |
| 51 | -// $folderName = $cmisProps['properties']['Name']['value']; | |
| 43 | + $ObjectService = new ObjectService(); | |
| 44 | + $ObjectService->startSession(self::$authData['username'], self::$authData['password']); | |
| 45 | + $cmisEntry = $ObjectService->getProperties($repositoryId, $folderId, false, false); | |
| 46 | + $folderName = $cmisEntry['properties']['Name']['value']; | |
| 47 | +// $feed = $this->getFolderChildrenFeed($NavigationService, $repositoryId, $newObjectId, $cmisEntry['properties']['Name']['value']); | |
| 52 | 48 | } |
| 53 | 49 | |
| 54 | - $username = $password = 'admin'; | |
| 55 | 50 | if (!empty($this->params[1]) && (($this->params[1] == 'children') || ($this->params[1] == 'descendants'))) |
| 56 | 51 | { |
| 57 | 52 | $NavigationService = new NavigationService(); |
| 58 | - $NavigationService->startSession($username, $password); | |
| 53 | + $NavigationService->startSession(self::$authData['username'], self::$authData['password']); | |
| 59 | 54 | |
| 60 | 55 | $feed = $this->getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $this->params[1]); |
| 61 | 56 | } |
| 62 | 57 | else |
| 63 | 58 | { |
| 64 | -// echo "UHUHUHUHUH: $folderId<BR>\n"; | |
| 65 | 59 | $ObjectService = new ObjectService(); |
| 66 | - $ObjectService->startSession($username, $password); | |
| 60 | + $ObjectService->startSession(self::$authData['username'], self::$authData['password']); | |
| 67 | 61 | |
| 68 | 62 | $feed = $this->getFolderFeed($ObjectService, $repositoryId, $folderId); |
| 69 | 63 | } |
| ... | ... | @@ -71,6 +65,84 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service |
| 71 | 65 | //Expose the responseFeed |
| 72 | 66 | $this->responseFeed = $feed; |
| 73 | 67 | } |
| 68 | + | |
| 69 | + public function POST_action() | |
| 70 | + { | |
| 71 | +// $username = $password = 'admin'; | |
| 72 | + $RepositoryService = new RepositoryService(); | |
| 73 | + $RepositoryService->startSession(self::$authData['username'], self::$authData['password']); | |
| 74 | + $repositories = $RepositoryService->getRepositories(); | |
| 75 | + $repositoryId = $repositories[0]['repositoryId']; | |
| 76 | + | |
| 77 | + $folderId = $this->params[0]; | |
| 78 | + $title = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'title'); | |
| 79 | + $summary = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'summary'); | |
| 80 | + | |
| 81 | + $properties = array('name' => $title, 'summary' => $summary); | |
| 82 | + | |
| 83 | + // determine whether this is a folder or a document create | |
| 84 | + // document create will have a content tag <atom:content> or <content> containing base64 encoding of the document | |
| 85 | + $content = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'content'); | |
| 86 | + if (is_null($content)) | |
| 87 | + $type = 'folder'; | |
| 88 | + else | |
| 89 | + $type = 'document'; | |
| 90 | + | |
| 91 | + // TODO what if mime-type is incorrect? CMISSpaces appears to be sending text/plain on an executable file. | |
| 92 | + // perhaps because the content is text/plain once base64 encoded? | |
| 93 | + // How to determine the actual content type? | |
| 94 | + /* | |
| 95 | + * <atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://www.cmis.org/2008/05"> | |
| 96 | + * <atom:title>setup.txt</atom:title> | |
| 97 | + * <atom:summary>setup.txt</atom:summary> | |
| 98 | + * <atom:content type="text/plain">dGhpcyBiZSBzb21lIHRlc3QgY29udGVudCBmb3IgYSBkb2N1bWVudCwgeWVzPw==</atom:content> | |
| 99 | + * <cmis:object> | |
| 100 | + * <cmis:properties> | |
| 101 | + * <cmis:propertyString cmis:name="ObjectTypeId"><cmis:value>document</cmis:value></cmis:propertyString> | |
| 102 | + * </cmis:properties> | |
| 103 | + * </cmis:object> | |
| 104 | + * </atom:entry> | |
| 105 | + */ | |
| 106 | + | |
| 107 | + $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->parsedXMLContent['@children']['cmis:object'] | |
| 108 | + [0]['@children']['cmis:properties'] | |
| 109 | + [0]['@children']); | |
| 110 | + | |
| 111 | + $ObjectService = new ObjectService(); | |
| 112 | + $ObjectService->startSession(self::$authData['username'], self::$authData['password']); | |
| 113 | + if ($type == 'folder') | |
| 114 | + $newObjectId = $ObjectService->createFolder($repositoryId, ucwords($cmisObjectProperties['ObjectTypeId']), $properties, $folderId); | |
| 115 | + else | |
| 116 | + $newObjectId = $ObjectService->createDocument($repositoryId, ucwords($cmisObjectProperties['ObjectTypeId']), $properties, $folderId, $content); | |
| 117 | + | |
| 118 | + // check if returned Object Id is a valid CMIS Object Id | |
| 119 | + $dummy = CMISUtil::decodeObjectId($newObjectId, $typeId); | |
| 120 | + if ($typeId != 'Unknown') | |
| 121 | + { | |
| 122 | + $this->setStatus(self::STATUS_CREATED); | |
| 123 | + if ($type == 'folder') | |
| 124 | + { | |
| 125 | + $feed = $this->getFolderFeed($ObjectService, $repositoryId, $newObjectId); | |
| 126 | + } | |
| 127 | + else | |
| 128 | + { | |
| 129 | + $NavigationService = new NavigationService(); | |
| 130 | + $NavigationService->startSession(self::$authData['username'], self::$authData['password']); | |
| 131 | + $cmisEntry = $ObjectService->getProperties($repositoryId, $folderId, false, false); | |
| 132 | + $feed = $this->getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $cmisEntry['properties']['Name']['value']); | |
| 133 | + } | |
| 134 | + } | |
| 135 | + else | |
| 136 | + { | |
| 137 | + $this->setStatus(self::STATUS_SERVER_ERROR); | |
| 138 | + $feed = new KT_cmis_atom_responseFeed(CMIS_APP_BASE_URI, 'Error: ' . self::STATUS_SERVER_ERROR); | |
| 139 | + $entry = $feed->newEntry(); | |
| 140 | + $feed->newField('error', $newObjectId['message'], $entry); | |
| 141 | + } | |
| 142 | + | |
| 143 | + //Expose the responseFeed | |
| 144 | + $this->responseFeed = $feed; | |
| 145 | + } | |
| 74 | 146 | |
| 75 | 147 | /** |
| 76 | 148 | * Retrieves children/descendants of the specified folder |
| ... | ... | @@ -81,7 +153,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service |
| 81 | 153 | * @param string $feedType children or descendants |
| 82 | 154 | * @return string CMIS AtomPub feed |
| 83 | 155 | */ |
| 84 | - private function getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $feedType) | |
| 156 | + private function getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $feedType = 'children') | |
| 85 | 157 | { |
| 86 | 158 | if ($feedType == 'children') |
| 87 | 159 | { |
| ... | ... | @@ -136,34 +208,6 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service |
| 136 | 208 | |
| 137 | 209 | return $feed; |
| 138 | 210 | } |
| 139 | - | |
| 140 | - // FIXME change how the drupal module works so that we don't need this anymore | |
| 141 | - private function getFolderData($query, &$folderName) | |
| 142 | - { | |
| 143 | - // FIXME really need to to avoid this! | |
| 144 | - $ktapi = new KTAPI(); | |
| 145 | - $ktapi->start_session('admin', 'admin'); | |
| 146 | - | |
| 147 | - $numQ = count($query); | |
| 148 | - $numFolders = $numQ-3; | |
| 149 | - $folderId = 1; | |
| 150 | - | |
| 151 | - if ($query[$numQ-1] == 'children' || $query[$numQ-1] == 'descendants') | |
| 152 | - { | |
| 153 | - $tree = $query[$numQ-1]; | |
| 154 | - } | |
| 155 | - | |
| 156 | - $start = 0; | |
| 157 | - while($start < $numFolders-1) | |
| 158 | - { | |
| 159 | - $folderName = urldecode($query[$numQ-$numFolders+$start]); | |
| 160 | - $folder = $ktapi->get_folder_by_name($folderName, $folderId); | |
| 161 | - $folderId = $folder->get_folderid(); | |
| 162 | - ++$start; | |
| 163 | - } | |
| 164 | - | |
| 165 | - return CMISUtil::encodeObjectId('Folder', $folderId); | |
| 166 | - } | |
| 167 | 211 | } |
| 168 | 212 | |
| 169 | 213 | /** |
| ... | ... | @@ -176,11 +220,11 @@ class KT_cmis_atom_service_types extends KT_cmis_atom_service |
| 176 | 220 | { |
| 177 | 221 | public function GET_action() |
| 178 | 222 | { |
| 179 | - $username = $password = 'admin'; | |
| 223 | +// $username = $password = 'admin'; | |
| 180 | 224 | $RepositoryService = new RepositoryService(); |
| 181 | 225 | // technically do not need to log in to access this information |
| 182 | 226 | // TODO consider requiring authentication even to access basic repository information |
| 183 | - $RepositoryService->startSession($username, $password); | |
| 227 | + $RepositoryService->startSession(self::$authData['username'], self::$authData['password']); | |
| 184 | 228 | |
| 185 | 229 | // fetch repository id |
| 186 | 230 | $repositories = $RepositoryService->getRepositories(); |
| ... | ... | @@ -205,11 +249,11 @@ class KT_cmis_atom_service_type extends KT_cmis_atom_service |
| 205 | 249 | { |
| 206 | 250 | public function GET_action() |
| 207 | 251 | { |
| 208 | - $username = $password = 'admin'; | |
| 252 | +// $username = $password = 'admin'; | |
| 209 | 253 | $RepositoryService = new RepositoryService(); |
| 210 | 254 | // technically do not need to log in to access this information |
| 211 | 255 | // TODO consider requiring authentication even to access basic repository information |
| 212 | - $RepositoryService->startSession($username, $password); | |
| 256 | + $RepositoryService->startSession(self::$authData['username'], self::$authData['password']); | |
| 213 | 257 | |
| 214 | 258 | // fetch repository id |
| 215 | 259 | $repositories = $RepositoryService->getRepositories(); |
| ... | ... | @@ -303,11 +347,11 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service |
| 303 | 347 | { |
| 304 | 348 | public function GET_action() |
| 305 | 349 | { |
| 306 | - $username = $password = 'admin'; | |
| 350 | +// $username = $password = 'admin'; | |
| 307 | 351 | $RepositoryService = new RepositoryService(); |
| 308 | 352 | $NavigationService = new NavigationService(); |
| 309 | 353 | |
| 310 | - $NavigationService->startSession($username, $password); | |
| 354 | + $NavigationService->startSession(self::$authData['username'], self::$authData['password']); | |
| 311 | 355 | |
| 312 | 356 | $repositories = $RepositoryService->getRepositories(); |
| 313 | 357 | $repositoryId = $repositories[0]['repositoryId']; |
| ... | ... | @@ -354,11 +398,11 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service |
| 354 | 398 | { |
| 355 | 399 | public function GET_action() |
| 356 | 400 | { |
| 357 | - $username = $password = 'admin'; | |
| 401 | +// $username = $password = 'admin'; | |
| 358 | 402 | $RepositoryService = new RepositoryService(); |
| 359 | 403 | |
| 360 | 404 | $ObjectService = new ObjectService(); |
| 361 | - $ObjectService->startSession($username, $password); | |
| 405 | + $ObjectService->startSession(self::$authData['username'], self::$authData['password']); | |
| 362 | 406 | |
| 363 | 407 | $repositories = $RepositoryService->getRepositories(); |
| 364 | 408 | $repositoryId = $repositories[0]['repositoryId']; | ... | ... |
webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php
| ... | ... | @@ -16,20 +16,22 @@ class KT_cmis_atom_service_helper { |
| 16 | 16 | // . strtolower($cmisEntry['properties']['ObjectTypeId']['value']), $entry); |
| 17 | 17 | |
| 18 | 18 | // echo $_SERVER['QUERY_STRING']."<BR>\n"; |
| 19 | - preg_match('/^\/?[^\/]*\/folder\/(.*)\/[^\/]*\/?$/', trim($_SERVER['QUERY_STRING'], '/'), $matches); | |
| 20 | - $path = $matches[1]; | |
| 21 | - $parent = preg_replace('/\/[^\/]*$/', '', $path); | |
| 22 | - // TODO fix path to work on old method, after fixing drupal module to not require extended path | |
| 19 | +// preg_match('/^\/?[^\/]*\/folder\/(.*)\/[^\/]*\/?$/', trim($_SERVER['QUERY_STRING'], '/'), $matches); | |
| 20 | +// $path = $matches[1]; | |
| 21 | +// $parent = preg_replace('/\/[^\/]*$/', '', $path); | |
| 22 | +// // TODO fix path to work on old method, after fixing drupal module to not require extended path | |
| 23 | +// | |
| 24 | +// $path = ''; | |
| 23 | 25 | |
| 24 | 26 | $id = $cmisEntry['properties']['ObjectId']['value']; |
| 25 | 27 | $entry = $feed->newEntry(); |
| 26 | 28 | $feed->newField('id', 'urn:uuid:' . $id, $entry); |
| 27 | - | |
| 29 | +// print_r($cmisEntry); | |
| 28 | 30 | // links |
| 29 | 31 | // TODO check parent link is correct, fix if needed |
| 30 | 32 | $link = $feed->newElement('link'); |
| 31 | 33 | $link->appendChild($feed->newAttr('rel','cmis-parent')); |
| 32 | - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/folder/' . $path)); | |
| 34 | + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/folder/' . $cmisEntry['properties']['ParentId']['value'])); | |
| 33 | 35 | $entry->appendChild($link); |
| 34 | 36 | |
| 35 | 37 | if (strtolower($cmisEntry['properties']['ObjectTypeId']['value']) == 'folder') |
| ... | ... | @@ -37,20 +39,20 @@ class KT_cmis_atom_service_helper { |
| 37 | 39 | // TODO check parent link is correct, fix if needed |
| 38 | 40 | $link = $feed->newElement('link'); |
| 39 | 41 | $link->appendChild($feed->newAttr('rel','cmis-folderparent')); |
| 40 | - $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/folder/' . $path)); | |
| 42 | + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/folder/' . $cmisEntry['properties']['ParentId']['value'])); | |
| 41 | 43 | $entry->appendChild($link); |
| 42 | 44 | $link = $feed->newElement('link'); |
| 43 | 45 | $link->appendChild($feed->newAttr('rel','cmis-children')); |
| 44 | 46 | $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/' |
| 45 | 47 | . strtolower($cmisEntry['properties']['ObjectTypeId']['value']) |
| 46 | - . '/' . $path . '/' . rawurlencode($cmisEntry['properties']['Name']['value']) | |
| 48 | + . '/' . $cmisEntry['properties']['ObjectId']['value'] | |
| 47 | 49 | . '/children')); |
| 48 | 50 | $entry->appendChild($link); |
| 49 | 51 | $link = $feed->newElement('link'); |
| 50 | 52 | $link->appendChild($feed->newAttr('rel','cmis-descendants')); |
| 51 | 53 | $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/' |
| 52 | 54 | . strtolower($cmisEntry['properties']['ObjectTypeId']['value']) |
| 53 | - . '/' . $path . '/' . rawurlencode($cmisEntry['properties']['Name']['value']) | |
| 55 | + . '/' . $cmisEntry['properties']['ObjectId']['value'] | |
| 54 | 56 | . '/descendants')); |
| 55 | 57 | $entry->appendChild($link); |
| 56 | 58 | } |
| ... | ... | @@ -164,18 +166,12 @@ class KT_cmis_atom_service_helper { |
| 164 | 166 | // TODO make this much more efficient than this messy method |
| 165 | 167 | static public function getFolderId($path, &$ktapi) |
| 166 | 168 | { |
| 167 | -// static public function getFolderData($query, &$folderName, &$tree) | |
| 168 | -// $ktapi = new KTAPI(); | |
| 169 | -// $ktapi->start_session('admin', 'admin'); | |
| 170 | - | |
| 171 | 169 | // lose first item |
| 172 | 170 | array_shift($path); |
| 173 | 171 | |
| 174 | 172 | $numQ = count($path); |
| 175 | -// echo $numQ."<BR>"; | |
| 176 | 173 | $numFolders = $numQ; |
| 177 | 174 | $folderId = 1; |
| 178 | -// echo $numFolders."<BR>"; | |
| 179 | 175 | |
| 180 | 176 | $start = 0; |
| 181 | 177 | while($start < $numFolders) |
| ... | ... | @@ -184,10 +180,7 @@ class KT_cmis_atom_service_helper { |
| 184 | 180 | // hack to fix drupal url encoding issue |
| 185 | 181 | $name = str_replace('%2520', '%20', $name); |
| 186 | 182 | |
| 187 | -// echo $name."<BR>"; | |
| 188 | - | |
| 189 | 183 | $folderName = urldecode($name); |
| 190 | -// echo $folderName."<BR>"; | |
| 191 | 184 | $folder = $ktapi->get_folder_by_name($folderName, $folderId); |
| 192 | 185 | $folderId = $folder->get_folderid(); |
| 193 | 186 | ++$start; |
| ... | ... | @@ -196,6 +189,31 @@ class KT_cmis_atom_service_helper { |
| 196 | 189 | return CMISUtil::encodeObjectId('Folder', $folderId); |
| 197 | 190 | } |
| 198 | 191 | |
| 192 | + static public function getCmisProperties($xmlArray) | |
| 193 | + { | |
| 194 | + $properties = array(); | |
| 195 | + | |
| 196 | + foreach($xmlArray as $cmisPropertyDefinition) | |
| 197 | + { | |
| 198 | + foreach($cmisPropertyDefinition as $propertyType => $propertyDefinition) | |
| 199 | + { | |
| 200 | + $properties[$propertyDefinition['@attributes']['cmis:name']] = $propertyDefinition['@children']['cmis:value'][0]['@value']; | |
| 201 | + } | |
| 202 | + } | |
| 203 | + | |
| 204 | + return $properties; | |
| 205 | + } | |
| 206 | + | |
| 207 | + static public function getAtomValues($xmlArray, $tag) | |
| 208 | + { | |
| 209 | + if (!is_null($xmlArray['atom:'.$tag])) | |
| 210 | + return $xmlArray['atom:'.$tag][0]['@value']; | |
| 211 | + else if (!is_null($xmlArray[$tag])) | |
| 212 | + return $xmlArray[$tag][0]['@value']; | |
| 213 | + | |
| 214 | + return null; | |
| 215 | + } | |
| 216 | + | |
| 199 | 217 | } |
| 200 | 218 | |
| 201 | 219 | ?> | ... | ... |
webservice/atompub/cmis/index.php
| ... | ... | @@ -59,6 +59,7 @@ $password = $_SERVER['PHP_AUTH_PW']; |
| 59 | 59 | /** |
| 60 | 60 | * Includes |
| 61 | 61 | */ |
| 62 | +include_once(KT_ATOM_LIB_FOLDER.'XMLns2array.inc.php'); | |
| 62 | 63 | include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_server.inc.php'); |
| 63 | 64 | include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_baseDoc.inc.php'); |
| 64 | 65 | include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_responseFeed.inc.php'); //Containing the response feed class allowing easy atom feed generation |
| ... | ... | @@ -66,7 +67,6 @@ include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_serviceDoc.inc.php'); / |
| 66 | 67 | include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_service.inc.php'); //Containing the servicedoc class allowing easy ServiceDocument generation |
| 67 | 68 | |
| 68 | 69 | include_once('KT_cmis_atom_server.services.inc.php'); |
| 69 | - | |
| 70 | 70 | //Start the AtomPubProtocol Routing Engine |
| 71 | 71 | $APP = new KT_cmis_atom_server(); |
| 72 | 72 | |
| ... | ... | @@ -91,7 +91,6 @@ $APP->addWorkspaceTag('dms','atom:title',$APP->repositoryInfo['repositoryName']) |
| 91 | 91 | * http://ktatompub/{folder/folder2/folder3/}service/param1/param2 |
| 92 | 92 | */ |
| 93 | 93 | // TODO consider a registerServices function which will, dependant on what is requested, register the appropriate services, keep the logic out of the index file |
| 94 | -// FIXME HACK! this should not happen every time, ONLY on a service doc request, except for request specific collection links | |
| 95 | 94 | $APP->registerService('dms', 'folder', 'KT_cmis_atom_service_folder', 'Root Folder Children Collection', |
| 96 | 95 | array(rawurlencode($APP->repositoryInfo['rootFolderId']), 'children'), 'root-children'); |
| 97 | 96 | $APP->registerService('dms', 'folder', 'KT_cmis_atom_service_folder', 'Root Folder Children Collection', | ... | ... |
webservice/classes/atompub/KT_atom_server.inc.php
| ... | ... | @@ -21,11 +21,10 @@ class KT_atom_server{ |
| 21 | 21 | * |
| 22 | 22 | */ |
| 23 | 23 | public function execute(){ |
| 24 | -// $_SERVER['QUERY_STRING'] = urldecode($_SERVER['QUERY_STRING']); | |
| 25 | 24 | $reqMethod=trim(strtoupper($_SERVER['REQUEST_METHOD'])); |
| 26 | 25 | $queryArray=split('/',trim($_SERVER['QUERY_STRING'],'/')); |
| 27 | 26 | $rawRequest=@file_get_contents('php://input'); |
| 28 | -//echo "\n\n".rawurldecode($_SERVER['QUERY_STRING'])."<BR><BR>\n\n"; | |
| 27 | + | |
| 29 | 28 | $workspace=strtolower(trim($queryArray[0])); |
| 30 | 29 | $serviceName=strtolower(trim($queryArray[1])); |
| 31 | 30 | $requestParams=array_slice($queryArray,2); |
| ... | ... | @@ -33,7 +32,7 @@ class KT_atom_server{ |
| 33 | 32 | $this->serviceName=$serviceName; |
| 34 | 33 | $this->method=$reqMethod; |
| 35 | 34 | $this->workspace=$workspace; |
| 36 | - | |
| 35 | + | |
| 37 | 36 | if($workspace=='servicedocument'){ |
| 38 | 37 | $this->serviceDocument(); |
| 39 | 38 | return; | ... | ... |
webservice/classes/atompub/KT_atom_service.inc.php
| 1 | 1 | <?php |
| 2 | 2 | class KT_atom_service{ |
| 3 | - const STATUS_OK ='200 OK'; | |
| 4 | - const STATUS_NOT_FOUND ='204 No Content'; | |
| 5 | - const STATUS_NOT_ALLOWED ='204 Not Allowed'; | |
| 6 | - const STATUS_NOT_AUTHENTICATED ='204 Not Authenticated'; | |
| 7 | - const STATUS_CREATED ='201 Created'; | |
| 8 | - const STATUS_UPDATED ='200 Updated'; | |
| 9 | - const STATUS_NOT_MODIFIED ='304 Not Modified'; //For use with ETag & If-None-Match headers. | |
| 10 | - const STATUS_PRECONDITION_FAILED='412 Precondition Failed'; //Could not update document because another a newer version exist on the server than the one you are trying to update | |
| 3 | + const STATUS_OK = '200 OK'; | |
| 4 | + const STATUS_NOT_FOUND = '204 No Content'; | |
| 5 | + const STATUS_NOT_ALLOWED = '204 Not Allowed'; | |
| 6 | + const STATUS_NOT_AUTHENTICATED = '204 Not Authenticated'; | |
| 7 | + const STATUS_CREATED = '201 Created'; | |
| 8 | + const STATUS_UPDATED = '200 Updated'; | |
| 9 | + const STATUS_NOT_MODIFIED = '304 Not Modified'; // For use with ETag & If-None-Match headers. | |
| 10 | + const STATUS_BAD_REQUEST = '400 Bad Request'; // Client issued a wrongly constructed request | |
| 11 | + const STATUS_PRECONDITION_FAILED = '412 Precondition Failed'; // Could not update document because another a newer version exist on the server than the one you are trying to update | |
| 12 | + const STATUS_SERVER_ERROR = '500 Internal Server Error'; // Server encountered an error processing the request | |
| 11 | 13 | |
| 12 | 14 | public $responseFeed=NULL; |
| 13 | 15 | public $responseHeader=NULL; |
| ... | ... | @@ -59,11 +61,17 @@ class KT_atom_service{ |
| 59 | 61 | return $this->responseFeed->render(); |
| 60 | 62 | } |
| 61 | 63 | |
| 62 | - protected function xml2array($xml){ | |
| 63 | - if(class_exists('')){ | |
| 64 | + protected function xml2array($xml) | |
| 65 | + { | |
| 66 | + if (trim($xml) == '') return array(); | |
| 67 | + | |
| 68 | + if(class_exists('XMLns2array')) | |
| 69 | + { | |
| 64 | 70 | $array=XMLns2array::parse($xml); |
| 65 | - }else{ | |
| 66 | - $array=json_decode(json_encode(@simplexml_load_string($xml)),true); | |
| 71 | + } | |
| 72 | + else | |
| 73 | + { | |
| 74 | + $array=json_decode(json_encode(@simplexml_load_string($xml)), true); | |
| 67 | 75 | } |
| 68 | 76 | return $array; |
| 69 | 77 | } | ... | ... |
webservice/classes/atompub/cmis/KT_cmis_atom_service.inc.php
| ... | ... | @@ -6,5 +6,31 @@ class KT_cmis_atom_service extends KT_atom_service { |
| 6 | 6 | |
| 7 | 7 | // override and extend as needed |
| 8 | 8 | |
| 9 | + static protected $authData = array(); | |
| 10 | + | |
| 11 | + protected function parseHeaders() | |
| 12 | + { | |
| 13 | +// echo "PARSE HEADERS\n"; | |
| 14 | + parent::parseHeaders(); | |
| 15 | +// echo "CHECKING HEADERS\n"; | |
| 16 | +// print_r($this->headers); | |
| 17 | +// print_r($_SERVER); | |
| 18 | + // attempt to fetch auth info from supplied headers | |
| 19 | + if (!empty($this->headers['Authorization'])) | |
| 20 | + { | |
| 21 | + $auth = base64_decode(preg_replace('/Basic */', '', $this->headers['Authorization'])); | |
| 22 | + $authData = explode(':', $auth); | |
| 23 | +// print_r($authData); | |
| 24 | + self::$authData['username'] = $authData[0]; | |
| 25 | + self::$authData['password'] = $authData[1]; | |
| 26 | + } | |
| 27 | + // if failed, attempt to fetch from $_SERVER array instead | |
| 28 | + else if (isset($_SERVER['PHP_AUTH_USER'])) | |
| 29 | + { | |
| 30 | + self::$authData['username'] = $_SERVER['PHP_AUTH_USER']; | |
| 31 | + self::$authData['password'] = $_SERVER['PHP_AUTH_PW']; | |
| 32 | + } | |
| 33 | + } | |
| 34 | + | |
| 9 | 35 | } |
| 10 | 36 | ?> |
| 11 | 37 | \ No newline at end of file | ... | ... |
webservice/classes/atompub/cmis/ObjectService.inc.php
| ... | ... | @@ -32,6 +32,59 @@ class ObjectService extends KTObjectService { |
| 32 | 32 | } |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | + /** | |
| 36 | + * Creates a new folder within the repository | |
| 37 | + * | |
| 38 | + * @param string $repositoryId The repository to which the folder must be added | |
| 39 | + * @param string $typeId Object Type id for the folder object being created | |
| 40 | + * @param array $properties Array of properties which must be applied to the created folder object | |
| 41 | + * @param string $folderId The id of the folder which will be the parent of the created folder object | |
| 42 | + * @return string $objectId The id of the created folder object | |
| 43 | + */ | |
| 44 | + function createFolder($repositoryId, $typeId, $properties, $folderId) | |
| 45 | + { | |
| 46 | + $result = parent::createFolder($repositoryId, $typeId, $properties, $folderId); | |
| 47 | + | |
| 48 | + if ($result['status_code'] == 0) | |
| 49 | + { | |
| 50 | + return $result['results']; | |
| 51 | + } | |
| 52 | + else | |
| 53 | + { | |
| 54 | + return $result; | |
| 55 | + } | |
| 56 | + } | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * Creates a new document within the repository | |
| 60 | + * | |
| 61 | + * @param string $repositoryId The repository to which the document must be added | |
| 62 | + * @param string $typeId Object Type id for the document object being created | |
| 63 | + * @param array $properties Array of properties which must be applied to the created document object | |
| 64 | + * @param string $folderId The id of the folder which will be the parent of the created document object | |
| 65 | + * This parameter is optional IF unfilingCapability is supported | |
| 66 | + * @param contentStream $contentStream optional content stream data | |
| 67 | + * @param string $versioningState optional version state value: checkedout/major/minor | |
| 68 | + * @return string $objectId The id of the created folder object | |
| 69 | + */ | |
| 70 | + // TODO throw ConstraintViolationException if: | |
| 71 | + // value of any of the properties violates the min/max/required/length constraints | |
| 72 | + // specified in the property definition in the Object-Type. | |
| 73 | + function createDocument($repositoryId, $typeId, $properties, $folderId = null, | |
| 74 | + $contentStream = null, $versioningState = null) | |
| 75 | + { | |
| 76 | + $result = parent::createDocument($repositoryId, $typeId, $properties, $folderId, $contentStream, $versioningState); | |
| 77 | + | |
| 78 | + if ($result['status_code'] == 0) | |
| 79 | + { | |
| 80 | + return $result['results']; | |
| 81 | + } | |
| 82 | + else | |
| 83 | + { | |
| 84 | + return $result; | |
| 85 | + } | |
| 86 | + } | |
| 87 | + | |
| 35 | 88 | } |
| 36 | 89 | |
| 37 | 90 | ?> | ... | ... |