Commit 07800ae62e89f829fe4ef2170376a29b4e55d27d

Authored by Paul Barrett
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
lib/api/ktcmis/config/repositories.xml
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 <repositoryURI>http://127.0.0.1/</repositoryURI> 13 <repositoryURI>http://127.0.0.1/</repositoryURI>
14 <repositoryInfo> 14 <repositoryInfo>
15 <repositoryId>0ad7de04-7914-41b1-b5ee-be9f0b626437</repositoryId> 15 <repositoryId>0ad7de04-7914-41b1-b5ee-be9f0b626437</repositoryId>
16 - <repositoryName>KnowledgeTree</repositoryName> 16 + <repositoryName>KnowledgeTree DMS</repositoryName>
17 <repositoryRelationship>self</repositoryRelationship> 17 <repositoryRelationship>self</repositoryRelationship>
18 <repositoryDescription>KnowledgeTree Repository</repositoryDescription> 18 <repositoryDescription>KnowledgeTree Repository</repositoryDescription>
19 <vendorName>KnowledgeTree</vendorName> 19 <vendorName>KnowledgeTree</vendorName>
lib/api/ktcmis/ktcmis.inc.php
@@ -70,18 +70,23 @@ class KTCMISBase { @@ -70,18 +70,23 @@ class KTCMISBase {
70 // TODO try to pick up existing session if possible, i.e. if the $session value is not empty 70 // TODO try to pick up existing session if possible, i.e. if the $session value is not empty
71 public function startSession($username, $password) 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 return self::$session; 90 return self::$session;
86 } 91 }
87 92
@@ -90,6 +95,11 @@ class KTCMISBase { @@ -90,6 +95,11 @@ class KTCMISBase {
90 return self::$ktapi; 95 return self::$ktapi;
91 } 96 }
92 97
  98 + public function getSession()
  99 + {
  100 + return self::$session;
  101 + }
  102 +
93 // TODO what about destroying sessions? only on logout (which is not offered by the CMIS clients tested so far) 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,6 +110,7 @@ class CMISDocumentObject extends CMISBaseObject {
110 } 110 }
111 111
112 $objectProperties = $object->get_detail(); 112 $objectProperties = $object->get_detail();
  113 +// print_r($objectProperties);
113 114
114 $this->_setPropertyInternal('ObjectId', CMISUtil::encodeObjectId($this->typeId, $objectProperties['document_id'])); 115 $this->_setPropertyInternal('ObjectId', CMISUtil::encodeObjectId($this->typeId, $objectProperties['document_id']));
115 // prevent doubled '/' chars 116 // prevent doubled '/' chars
@@ -131,6 +132,7 @@ class CMISDocumentObject extends CMISBaseObject { @@ -131,6 +132,7 @@ class CMISDocumentObject extends CMISBaseObject {
131 $this->_setPropertyInternal('LastModificationDate', $objectProperties['modified_date']); 132 $this->_setPropertyInternal('LastModificationDate', $objectProperties['modified_date']);
132 $this->_setPropertyInternal('ChangeToken', null); 133 $this->_setPropertyInternal('ChangeToken', null);
133 $this->_setPropertyInternal('Name', $objectProperties['title']); 134 $this->_setPropertyInternal('Name', $objectProperties['title']);
  135 + $this->_setPropertyInternal('ParentId', $objectProperties['folder_id']);
134 $this->_setPropertyInternal('IsImmutable', $objectProperties['is_immutable']); 136 $this->_setPropertyInternal('IsImmutable', $objectProperties['is_immutable']);
135 // NOTE if access to older versions is allowed, this will need to be checked, else just set to yes 137 // NOTE if access to older versions is allowed, this will need to be checked, else just set to yes
136 // see ktapi::get_document_version_history 138 // see ktapi::get_document_version_history
lib/api/ktcmis/services/CMISObjectService.inc.php
@@ -262,6 +262,12 @@ class CMISObjectService { @@ -262,6 +262,12 @@ class CMISObjectService {
262 throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')'); 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 $response = $this->ktapi->create_folder((int)$folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = ''); 271 $response = $this->ktapi->create_folder((int)$folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = '');
266 if ($response['status_code'] != 0) 272 if ($response['status_code'] != 0)
267 { 273 {
lib/api/ktcmis/util/CMISUtil.inc.php
@@ -86,6 +86,12 @@ class CMISUtil { @@ -86,6 +86,12 @@ class CMISUtil {
86 */ 86 */
87 static public function decodeObjectId($objectId, &$typeId = null) 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 $typeId = null; 95 $typeId = null;
90 96
91 preg_match('/(\D)(\d*)/', $objectId, $matches); 97 preg_match('/(\D)(\d*)/', $objectId, $matches);
@@ -240,14 +246,11 @@ class CMISUtil { @@ -240,14 +246,11 @@ class CMISUtil {
240 'value' => $properties->getValue('Name')); 246 'value' => $properties->getValue('Name'));
241 $object['Author'] = array('value' => $properties->getValue('Author')); 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 // TODO should check for content stream data before filling these in 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 $object['properties']['ContentStreamLength'] = array('type' => $properties->getFieldType('ContentStreamLength'), 255 $object['properties']['ContentStreamLength'] = array('type' => $properties->getFieldType('ContentStreamLength'),
253 'value' => $properties->getValue('ContentStreamLength')); 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,14 +17,15 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service
17 { 17 {
18 public function GET_action() 18 public function GET_action()
19 { 19 {
20 - $username = $password = 'admin';  
21 $RepositoryService = new RepositoryService(); 20 $RepositoryService = new RepositoryService();
22 - $RepositoryService->startSession($username, $password); 21 + $RepositoryService->startSession(self::$authData['username'], self::$authData['password']);
23 $repositories = $RepositoryService->getRepositories(); 22 $repositories = $RepositoryService->getRepositories();
24 $repositoryId = $repositories[0]['repositoryId']; 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 if (urldecode($this->params[0]) == 'Root Folder') 29 if (urldecode($this->params[0]) == 'Root Folder')
29 { 30 {
30 $folderId = CMISUtil::encodeObjectId('Folder', 1); 31 $folderId = CMISUtil::encodeObjectId('Folder', 1);
@@ -35,35 +36,28 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service @@ -35,35 +36,28 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service
35 { 36 {
36 $ktapi =& $RepositoryService->getInterface(); 37 $ktapi =& $RepositoryService->getInterface();
37 $folderId = KT_cmis_atom_service_helper::getFolderId($this->params, $ktapi); 38 $folderId = KT_cmis_atom_service_helper::getFolderId($this->params, $ktapi);
38 -// echo "DA FOLDER ID IS $folderId<BR>";  
39 } 39 }
40 else 40 else
41 { 41 {
42 $folderId = $this->params[0]; 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 if (!empty($this->params[1]) && (($this->params[1] == 'children') || ($this->params[1] == 'descendants'))) 50 if (!empty($this->params[1]) && (($this->params[1] == 'children') || ($this->params[1] == 'descendants')))
56 { 51 {
57 $NavigationService = new NavigationService(); 52 $NavigationService = new NavigationService();
58 - $NavigationService->startSession($username, $password); 53 + $NavigationService->startSession(self::$authData['username'], self::$authData['password']);
59 54
60 $feed = $this->getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $this->params[1]); 55 $feed = $this->getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $this->params[1]);
61 } 56 }
62 else 57 else
63 { 58 {
64 -// echo "UHUHUHUHUH: $folderId<BR>\n";  
65 $ObjectService = new ObjectService(); 59 $ObjectService = new ObjectService();
66 - $ObjectService->startSession($username, $password); 60 + $ObjectService->startSession(self::$authData['username'], self::$authData['password']);
67 61
68 $feed = $this->getFolderFeed($ObjectService, $repositoryId, $folderId); 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,6 +65,84 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service
71 //Expose the responseFeed 65 //Expose the responseFeed
72 $this->responseFeed = $feed; 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 * Retrieves children/descendants of the specified folder 148 * Retrieves children/descendants of the specified folder
@@ -81,7 +153,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service @@ -81,7 +153,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service
81 * @param string $feedType children or descendants 153 * @param string $feedType children or descendants
82 * @return string CMIS AtomPub feed 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 if ($feedType == 'children') 158 if ($feedType == 'children')
87 { 159 {
@@ -136,34 +208,6 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service @@ -136,34 +208,6 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service
136 208
137 return $feed; 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,11 +220,11 @@ class KT_cmis_atom_service_types extends KT_cmis_atom_service
176 { 220 {
177 public function GET_action() 221 public function GET_action()
178 { 222 {
179 - $username = $password = 'admin'; 223 +// $username = $password = 'admin';
180 $RepositoryService = new RepositoryService(); 224 $RepositoryService = new RepositoryService();
181 // technically do not need to log in to access this information 225 // technically do not need to log in to access this information
182 // TODO consider requiring authentication even to access basic repository information 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 // fetch repository id 229 // fetch repository id
186 $repositories = $RepositoryService->getRepositories(); 230 $repositories = $RepositoryService->getRepositories();
@@ -205,11 +249,11 @@ class KT_cmis_atom_service_type extends KT_cmis_atom_service @@ -205,11 +249,11 @@ class KT_cmis_atom_service_type extends KT_cmis_atom_service
205 { 249 {
206 public function GET_action() 250 public function GET_action()
207 { 251 {
208 - $username = $password = 'admin'; 252 +// $username = $password = 'admin';
209 $RepositoryService = new RepositoryService(); 253 $RepositoryService = new RepositoryService();
210 // technically do not need to log in to access this information 254 // technically do not need to log in to access this information
211 // TODO consider requiring authentication even to access basic repository information 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 // fetch repository id 258 // fetch repository id
215 $repositories = $RepositoryService->getRepositories(); 259 $repositories = $RepositoryService->getRepositories();
@@ -303,11 +347,11 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service @@ -303,11 +347,11 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service
303 { 347 {
304 public function GET_action() 348 public function GET_action()
305 { 349 {
306 - $username = $password = 'admin'; 350 +// $username = $password = 'admin';
307 $RepositoryService = new RepositoryService(); 351 $RepositoryService = new RepositoryService();
308 $NavigationService = new NavigationService(); 352 $NavigationService = new NavigationService();
309 353
310 - $NavigationService->startSession($username, $password); 354 + $NavigationService->startSession(self::$authData['username'], self::$authData['password']);
311 355
312 $repositories = $RepositoryService->getRepositories(); 356 $repositories = $RepositoryService->getRepositories();
313 $repositoryId = $repositories[0]['repositoryId']; 357 $repositoryId = $repositories[0]['repositoryId'];
@@ -354,11 +398,11 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service @@ -354,11 +398,11 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service
354 { 398 {
355 public function GET_action() 399 public function GET_action()
356 { 400 {
357 - $username = $password = 'admin'; 401 +// $username = $password = 'admin';
358 $RepositoryService = new RepositoryService(); 402 $RepositoryService = new RepositoryService();
359 403
360 $ObjectService = new ObjectService(); 404 $ObjectService = new ObjectService();
361 - $ObjectService->startSession($username, $password); 405 + $ObjectService->startSession(self::$authData['username'], self::$authData['password']);
362 406
363 $repositories = $RepositoryService->getRepositories(); 407 $repositories = $RepositoryService->getRepositories();
364 $repositoryId = $repositories[0]['repositoryId']; 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,20 +16,22 @@ class KT_cmis_atom_service_helper {
16 // . strtolower($cmisEntry['properties']['ObjectTypeId']['value']), $entry); 16 // . strtolower($cmisEntry['properties']['ObjectTypeId']['value']), $entry);
17 17
18 // echo $_SERVER['QUERY_STRING']."<BR>\n"; 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 $id = $cmisEntry['properties']['ObjectId']['value']; 26 $id = $cmisEntry['properties']['ObjectId']['value'];
25 $entry = $feed->newEntry(); 27 $entry = $feed->newEntry();
26 $feed->newField('id', 'urn:uuid:' . $id, $entry); 28 $feed->newField('id', 'urn:uuid:' . $id, $entry);
27 - 29 +// print_r($cmisEntry);
28 // links 30 // links
29 // TODO check parent link is correct, fix if needed 31 // TODO check parent link is correct, fix if needed
30 $link = $feed->newElement('link'); 32 $link = $feed->newElement('link');
31 $link->appendChild($feed->newAttr('rel','cmis-parent')); 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 $entry->appendChild($link); 35 $entry->appendChild($link);
34 36
35 if (strtolower($cmisEntry['properties']['ObjectTypeId']['value']) == 'folder') 37 if (strtolower($cmisEntry['properties']['ObjectTypeId']['value']) == 'folder')
@@ -37,20 +39,20 @@ class KT_cmis_atom_service_helper { @@ -37,20 +39,20 @@ class KT_cmis_atom_service_helper {
37 // TODO check parent link is correct, fix if needed 39 // TODO check parent link is correct, fix if needed
38 $link = $feed->newElement('link'); 40 $link = $feed->newElement('link');
39 $link->appendChild($feed->newAttr('rel','cmis-folderparent')); 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 $entry->appendChild($link); 43 $entry->appendChild($link);
42 $link = $feed->newElement('link'); 44 $link = $feed->newElement('link');
43 $link->appendChild($feed->newAttr('rel','cmis-children')); 45 $link->appendChild($feed->newAttr('rel','cmis-children'));
44 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/' 46 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/'
45 . strtolower($cmisEntry['properties']['ObjectTypeId']['value']) 47 . strtolower($cmisEntry['properties']['ObjectTypeId']['value'])
46 - . '/' . $path . '/' . rawurlencode($cmisEntry['properties']['Name']['value']) 48 + . '/' . $cmisEntry['properties']['ObjectId']['value']
47 . '/children')); 49 . '/children'));
48 $entry->appendChild($link); 50 $entry->appendChild($link);
49 $link = $feed->newElement('link'); 51 $link = $feed->newElement('link');
50 $link->appendChild($feed->newAttr('rel','cmis-descendants')); 52 $link->appendChild($feed->newAttr('rel','cmis-descendants'));
51 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/' 53 $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $feed->workspace . '/'
52 . strtolower($cmisEntry['properties']['ObjectTypeId']['value']) 54 . strtolower($cmisEntry['properties']['ObjectTypeId']['value'])
53 - . '/' . $path . '/' . rawurlencode($cmisEntry['properties']['Name']['value']) 55 + . '/' . $cmisEntry['properties']['ObjectId']['value']
54 . '/descendants')); 56 . '/descendants'));
55 $entry->appendChild($link); 57 $entry->appendChild($link);
56 } 58 }
@@ -164,18 +166,12 @@ class KT_cmis_atom_service_helper { @@ -164,18 +166,12 @@ class KT_cmis_atom_service_helper {
164 // TODO make this much more efficient than this messy method 166 // TODO make this much more efficient than this messy method
165 static public function getFolderId($path, &$ktapi) 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 // lose first item 169 // lose first item
172 array_shift($path); 170 array_shift($path);
173 171
174 $numQ = count($path); 172 $numQ = count($path);
175 -// echo $numQ."<BR>";  
176 $numFolders = $numQ; 173 $numFolders = $numQ;
177 $folderId = 1; 174 $folderId = 1;
178 -// echo $numFolders."<BR>";  
179 175
180 $start = 0; 176 $start = 0;
181 while($start < $numFolders) 177 while($start < $numFolders)
@@ -184,10 +180,7 @@ class KT_cmis_atom_service_helper { @@ -184,10 +180,7 @@ class KT_cmis_atom_service_helper {
184 // hack to fix drupal url encoding issue 180 // hack to fix drupal url encoding issue
185 $name = str_replace('%2520', '%20', $name); 181 $name = str_replace('%2520', '%20', $name);
186 182
187 -// echo $name."<BR>";  
188 -  
189 $folderName = urldecode($name); 183 $folderName = urldecode($name);
190 -// echo $folderName."<BR>";  
191 $folder = $ktapi->get_folder_by_name($folderName, $folderId); 184 $folder = $ktapi->get_folder_by_name($folderName, $folderId);
192 $folderId = $folder->get_folderid(); 185 $folderId = $folder->get_folderid();
193 ++$start; 186 ++$start;
@@ -196,6 +189,31 @@ class KT_cmis_atom_service_helper { @@ -196,6 +189,31 @@ class KT_cmis_atom_service_helper {
196 return CMISUtil::encodeObjectId('Folder', $folderId); 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[&#39;PHP_AUTH_PW&#39;]; @@ -59,6 +59,7 @@ $password = $_SERVER[&#39;PHP_AUTH_PW&#39;];
59 /** 59 /**
60 * Includes 60 * Includes
61 */ 61 */
  62 +include_once(KT_ATOM_LIB_FOLDER.'XMLns2array.inc.php');
62 include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_server.inc.php'); 63 include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_server.inc.php');
63 include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_baseDoc.inc.php'); 64 include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_baseDoc.inc.php');
64 include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_responseFeed.inc.php'); //Containing the response feed class allowing easy atom feed generation 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.&#39;KT_cmis_atom_serviceDoc.inc.php&#39;); / @@ -66,7 +67,6 @@ include_once(CMIS_ATOM_LIB_FOLDER.&#39;KT_cmis_atom_serviceDoc.inc.php&#39;); /
66 include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_service.inc.php'); //Containing the servicedoc class allowing easy ServiceDocument generation 67 include_once(CMIS_ATOM_LIB_FOLDER.'KT_cmis_atom_service.inc.php'); //Containing the servicedoc class allowing easy ServiceDocument generation
67 68
68 include_once('KT_cmis_atom_server.services.inc.php'); 69 include_once('KT_cmis_atom_server.services.inc.php');
69 -  
70 //Start the AtomPubProtocol Routing Engine 70 //Start the AtomPubProtocol Routing Engine
71 $APP = new KT_cmis_atom_server(); 71 $APP = new KT_cmis_atom_server();
72 72
@@ -91,7 +91,6 @@ $APP-&gt;addWorkspaceTag(&#39;dms&#39;,&#39;atom:title&#39;,$APP-&gt;repositoryInfo[&#39;repositoryName&#39;]) @@ -91,7 +91,6 @@ $APP-&gt;addWorkspaceTag(&#39;dms&#39;,&#39;atom:title&#39;,$APP-&gt;repositoryInfo[&#39;repositoryName&#39;])
91 * http://ktatompub/{folder/folder2/folder3/}service/param1/param2 91 * http://ktatompub/{folder/folder2/folder3/}service/param1/param2
92 */ 92 */
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 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 $APP->registerService('dms', 'folder', 'KT_cmis_atom_service_folder', 'Root Folder Children Collection', 94 $APP->registerService('dms', 'folder', 'KT_cmis_atom_service_folder', 'Root Folder Children Collection',
96 array(rawurlencode($APP->repositoryInfo['rootFolderId']), 'children'), 'root-children'); 95 array(rawurlencode($APP->repositoryInfo['rootFolderId']), 'children'), 'root-children');
97 $APP->registerService('dms', 'folder', 'KT_cmis_atom_service_folder', 'Root Folder Children Collection', 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,11 +21,10 @@ class KT_atom_server{
21 * 21 *
22 */ 22 */
23 public function execute(){ 23 public function execute(){
24 -// $_SERVER['QUERY_STRING'] = urldecode($_SERVER['QUERY_STRING']);  
25 $reqMethod=trim(strtoupper($_SERVER['REQUEST_METHOD'])); 24 $reqMethod=trim(strtoupper($_SERVER['REQUEST_METHOD']));
26 $queryArray=split('/',trim($_SERVER['QUERY_STRING'],'/')); 25 $queryArray=split('/',trim($_SERVER['QUERY_STRING'],'/'));
27 $rawRequest=@file_get_contents('php://input'); 26 $rawRequest=@file_get_contents('php://input');
28 -//echo "\n\n".rawurldecode($_SERVER['QUERY_STRING'])."<BR><BR>\n\n"; 27 +
29 $workspace=strtolower(trim($queryArray[0])); 28 $workspace=strtolower(trim($queryArray[0]));
30 $serviceName=strtolower(trim($queryArray[1])); 29 $serviceName=strtolower(trim($queryArray[1]));
31 $requestParams=array_slice($queryArray,2); 30 $requestParams=array_slice($queryArray,2);
@@ -33,7 +32,7 @@ class KT_atom_server{ @@ -33,7 +32,7 @@ class KT_atom_server{
33 $this->serviceName=$serviceName; 32 $this->serviceName=$serviceName;
34 $this->method=$reqMethod; 33 $this->method=$reqMethod;
35 $this->workspace=$workspace; 34 $this->workspace=$workspace;
36 - 35 +
37 if($workspace=='servicedocument'){ 36 if($workspace=='servicedocument'){
38 $this->serviceDocument(); 37 $this->serviceDocument();
39 return; 38 return;
webservice/classes/atompub/KT_atom_service.inc.php
1 <?php 1 <?php
2 class KT_atom_service{ 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 public $responseFeed=NULL; 14 public $responseFeed=NULL;
13 public $responseHeader=NULL; 15 public $responseHeader=NULL;
@@ -59,11 +61,17 @@ class KT_atom_service{ @@ -59,11 +61,17 @@ class KT_atom_service{
59 return $this->responseFeed->render(); 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 $array=XMLns2array::parse($xml); 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 return $array; 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,5 +6,31 @@ class KT_cmis_atom_service extends KT_atom_service {
6 6
7 // override and extend as needed 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 \ No newline at end of file 37 \ No newline at end of file
webservice/classes/atompub/cmis/ObjectService.inc.php
@@ -32,6 +32,59 @@ class ObjectService extends KTObjectService { @@ -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 ?>