Commit e3db559fb1e17dc1519f8b693d37f3c97665bc11

Authored by Jarrett Jordaan
2 parents 9ff051f8 1e663d1c

Merge branch 'edge' of git@github.com:ktgit/knowledgetree into edge

ktapi/ktapi.inc.php
@@ -2928,7 +2928,7 @@ class KTAPI @@ -2928,7 +2928,7 @@ class KTAPI
2928 * @param string $tempfilename 2928 * @param string $tempfilename
2929 * @return kt_document_detail. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_FOLDER, KTWS_ERR_INVALID_DOCUMENT or KTWS_SUCCESS 2929 * @return kt_document_detail. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_FOLDER, KTWS_ERR_INVALID_DOCUMENT or KTWS_SUCCESS
2930 */ 2930 */
2931 - public function checkin_document($document_id, $filename, $reason, $tempfilename, $major_update, 2931 + public function checkin_document($document_id, $filename, $reason, $tempfilename, $major_update,
2932 $sig_username = '', $sig_password = '') 2932 $sig_username = '', $sig_password = '')
2933 { 2933 {
2934 $response = $this->_check_electronic_signature($document_id, $sig_username, $sig_password, $reason, $reason, 2934 $response = $this->_check_electronic_signature($document_id, $sig_username, $sig_password, $reason, $reason,
lib/api/ktcmis/classes/CMISDocumentPropertyCollection.inc.php
@@ -71,6 +71,7 @@ class CMISDocumentPropertyCollection extends CMISPropertyCollection { @@ -71,6 +71,7 @@ class CMISDocumentPropertyCollection extends CMISPropertyCollection {
71 'ContentStreamMimeType' => 'propertyString', 71 'ContentStreamMimeType' => 'propertyString',
72 'ContentStreamFilename' => 'propertyString', 72 'ContentStreamFilename' => 'propertyString',
73 'ContentStreamUri' => 'propertyUri', 73 'ContentStreamUri' => 'propertyUri',
  74 + 'IsLatestVersion' => 'propertyBoolean',
74 'IsVersionSeriesCheckedOut' => 'propertyBoolean', 75 'IsVersionSeriesCheckedOut' => 'propertyBoolean',
75 'VersionSeriesCheckedOutBy' => 'propertyString', 76 'VersionSeriesCheckedOutBy' => 'propertyString',
76 'VersionSeriesCheckedOutId' => 'propertyId', 77 'VersionSeriesCheckedOutId' => 'propertyId',
lib/api/ktcmis/ktcmis.inc.php
@@ -874,10 +874,10 @@ class KTVersioningService extends KTCMISBase { @@ -874,10 +874,10 @@ class KTVersioningService extends KTCMISBase {
874 * @param string $checkinComment [optional] 874 * @param string $checkinComment [optional]
875 * @return string $documentId 875 * @return string $documentId
876 */ 876 */
877 - public function checkIn($repositoryId, $documentId, $major, $changeToken = '', $properties = array(), $contentStream = null, $checkinComment = '') 877 + public function checkIn($repositoryId, $documentId, $major, $contentStream = null, $changeToken = '', $properties = array(), $checkinComment = '')
878 { 878 {
879 try { 879 try {
880 - $result = $this->VersioningService->checkIn($repositoryId, $documentId, $major, $changeToken, $properties, $contentStream, $checkinComment); 880 + $result = $this->VersioningService->checkIn($repositoryId, $documentId, $major, $contentStream, $changeToken, $properties, $checkinComment);
881 } 881 }
882 catch (Exception $e) 882 catch (Exception $e)
883 { 883 {
lib/api/ktcmis/services/CMISObjectService.inc.php
@@ -61,7 +61,7 @@ class CMISObjectService { @@ -61,7 +61,7 @@ class CMISObjectService {
61 // NOTE The latter method has been adopted for the moment 61 // NOTE The latter method has been adopted for the moment
62 catch (Exception $e) 62 catch (Exception $e)
63 { 63 {
64 - throw new ConstraintViolationException('Object is not of base type document. ' . $e->getMessage()); 64 + throw new ConstraintViolationException('Object base type could not be determined. ' . $e->getMessage());
65 } 65 }
66 66
67 if ($typeDefinition['attributes']['baseType'] != 'document') 67 if ($typeDefinition['attributes']['baseType'] != 'document')
@@ -103,49 +103,41 @@ class CMISObjectService { @@ -103,49 +103,41 @@ class CMISObjectService {
103 } 103 }
104 } 104 }
105 105
106 - if (!$typeAllowed)  
107 - { 106 + if (!$typeAllowed) {
108 throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')'); 107 throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')');
109 } 108 }
110 109
111 // if content stream is required and no content stream is supplied, throw a ConstraintViolationException 110 // if content stream is required and no content stream is supplied, throw a ConstraintViolationException
112 - if (($typeDefinition['attributes']['contentStreamAllowed'] == 'required') && is_null($contentStream))  
113 - { 111 + if (($typeDefinition['attributes']['contentStreamAllowed'] == 'required') && is_null($contentStream)) {
114 throw new ConstraintViolationException('This repository requires a content stream for document creation. ' 112 throw new ConstraintViolationException('This repository requires a content stream for document creation. '
115 . 'Refusing to create an empty document'); 113 . 'Refusing to create an empty document');
116 } 114 }
117 - else if (($typeDefinition['attributes']['contentStreamAllowed'] == 'notAllowed') && !empty($contentStream))  
118 - { 115 + else if (($typeDefinition['attributes']['contentStreamAllowed'] == 'notAllowed') && !empty($contentStream)) {
119 throw new StreamNotSupportedException('Content Streams are not supported'); 116 throw new StreamNotSupportedException('Content Streams are not supported');
120 } 117 }
121 118
122 // if versionable attribute is set to false and versioningState is supplied, throw a ConstraintViolationException 119 // if versionable attribute is set to false and versioningState is supplied, throw a ConstraintViolationException
123 - if (!$typeDefinition['attributes']['versionable'] && !empty($versioningState))  
124 - { 120 + if (!$typeDefinition['attributes']['versionable'] && !empty($versioningState)) {
125 throw new ConstraintViolationException('This repository does not support versioning'); 121 throw new ConstraintViolationException('This repository does not support versioning');
126 } 122 }
127 123
128 // TODO deal with $versioningState when supplied 124 // TODO deal with $versioningState when supplied
129 125
130 // set title and name identical if only one submitted 126 // set title and name identical if only one submitted
131 - if ($properties['title'] == '')  
132 - { 127 + if ($properties['title'] == '') {
133 $properties['title'] = $properties['name']; 128 $properties['title'] = $properties['name'];
134 } 129 }
135 - else if ($properties['name'] == '')  
136 - { 130 + else if ($properties['name'] == '') {
137 $properties['name'] = $properties['title']; 131 $properties['name'] = $properties['title'];
138 } 132 }
139 133
140 // if name is blank throw exception (check type) - using invalidArgument Exception for now 134 // if name is blank throw exception (check type) - using invalidArgument Exception for now
141 - if (trim($properties['name']) == '')  
142 - { 135 + if (trim($properties['name']) == '') {
143 throw new InvalidArgumentException('Refusing to create an un-named document'); 136 throw new InvalidArgumentException('Refusing to create an un-named document');
144 } 137 }
145 138
146 // TODO also set to Default if a non-supported type is submitted 139 // TODO also set to Default if a non-supported type is submitted
147 - if ($properties['type'] == '')  
148 - { 140 + if ($properties['type'] == '') {
149 $properties['type'] = 'Default'; 141 $properties['type'] = 'Default';
150 } 142 }
151 143
@@ -154,17 +146,7 @@ class CMISObjectService { @@ -154,17 +146,7 @@ class CMISObjectService {
154 // this check isn't strictly necessary; however it is needed for a repository which does not support content streams 146 // this check isn't strictly necessary; however it is needed for a repository which does not support content streams
155 if (!is_null($contentStream)) 147 if (!is_null($contentStream))
156 { 148 {
157 - // TODO consider checking whether content is encoded (currently we expect encoded)  
158 - // TODO choose between this and the alternative decode function (see CMISUtil class)  
159 - // this will require some basic benchmarking  
160 - $contentStream = CMISUtil::decodeChunkedContentStream($contentStream);  
161 -  
162 - // NOTE There is a function in CMISUtil to do this, written for the unit tests but since KTUploadManager exists  
163 - // and has more functionality which could come in useful at some point I decided to go with that instead  
164 - // (did not know this existed when I wrote the CMISUtil function)  
165 - $uploadManager = new KTUploadManager();  
166 - // assumes already decoded from base64, should use store_base64_file if not  
167 - $tempfilename = $uploadManager->store_file($contentStream, 'cmis_'); 149 + $tempfilename = CMISUtil::createTemporaryFile($contentStream);
168 150
169 // metadata 151 // metadata
170 $metadata = array(); 152 $metadata = array();
@@ -192,12 +174,10 @@ class CMISObjectService { @@ -192,12 +174,10 @@ class CMISObjectService {
192 ); 174 );
193 } 175 }
194 176
195 - if (!empty($properties['category']))  
196 - { 177 + if (!empty($properties['category'])) {
197 $category = $properties['category']; 178 $category = $properties['category'];
198 } 179 }
199 - else  
200 - { 180 + else {
201 $category = 'Miscellaneous'; 181 $category = 'Miscellaneous';
202 } 182 }
203 183
@@ -231,12 +211,10 @@ class CMISObjectService { @@ -231,12 +211,10 @@ class CMISObjectService {
231 $KTMime = new KTMime(); 211 $KTMime = new KTMime();
232 $mimetype = $KTMime->getMimeTypeFromFile($tempfilename); 212 $mimetype = $KTMime->getMimeTypeFromFile($tempfilename);
233 preg_match('/^([^\/]*)\/([^\/]*)/', $mimetype, $matches); 213 preg_match('/^([^\/]*)\/([^\/]*)/', $mimetype, $matches);
234 - if (($matches[1] == 'text') || ($matches[1] == 'image') || ($matches[1] == 'audio'))  
235 - { 214 + if (($matches[1] == 'text') || ($matches[1] == 'image') || ($matches[1] == 'audio')) {
236 $mediatype = ucwords($matches[1]); 215 $mediatype = ucwords($matches[1]);
237 } 216 }
238 - else if (($matches[2] == 'pdf') || ($matches[2] == 'msword'))  
239 - { 217 + else if (($matches[2] == 'pdf') || ($matches[2] == 'msword')) {
240 $mediatype = 'Text'; 218 $mediatype = 'Text';
241 } 219 }
242 220
@@ -262,12 +240,10 @@ class CMISObjectService { @@ -262,12 +240,10 @@ class CMISObjectService {
262 $response = $this->ktapi->add_document_with_metadata((int)$folderId, $properties['title'], $properties['name'], 240 $response = $this->ktapi->add_document_with_metadata((int)$folderId, $properties['title'], $properties['name'],
263 $properties['type'], $tempfilename, $metadata, $sysdata); 241 $properties['type'], $tempfilename, $metadata, $sysdata);
264 242
265 - if ($response['status_code'] != 0)  
266 - { 243 + if ($response['status_code'] != 0) {
267 throw new StorageException('The repository was unable to create the document. ' . $response['message']); 244 throw new StorageException('The repository was unable to create the document. ' . $response['message']);
268 } 245 }
269 - else  
270 - { 246 + else {
271 $objectId = CMISUtil::encodeObjectId('Document', $response['results']['document_id']); 247 $objectId = CMISUtil::encodeObjectId('Document', $response['results']['document_id']);
272 } 248 }
273 249
@@ -314,13 +290,11 @@ class CMISObjectService { @@ -314,13 +290,11 @@ class CMISObjectService {
314 // exception propogate upward... 290 // exception propogate upward...
315 // Alternatively: throw new exception with original exception message appended 291 // Alternatively: throw new exception with original exception message appended
316 // NOTE The latter method has been adopted for the moment 292 // NOTE The latter method has been adopted for the moment
317 - catch (Exception $e)  
318 - { 293 + catch (Exception $e) {
319 throw new ConstraintViolationException('Object is not of base type folder. ' . $e->getMessage()); 294 throw new ConstraintViolationException('Object is not of base type folder. ' . $e->getMessage());
320 } 295 }
321 296
322 - if ($typeDefinition['attributes']['baseType'] != 'folder')  
323 - { 297 + if ($typeDefinition['attributes']['baseType'] != 'folder') {
324 throw new ConstraintViolationException('Object is not of base type folder'); 298 throw new ConstraintViolationException('Object is not of base type folder');
325 } 299 }
326 300
@@ -333,20 +307,17 @@ class CMISObjectService { @@ -333,20 +307,17 @@ class CMISObjectService {
333 // if parent folder is not allowed to hold this type, throw exception 307 // if parent folder is not allowed to hold this type, throw exception
334 $CMISFolder = new CMISFolderObject($folderId, $this->ktapi); 308 $CMISFolder = new CMISFolderObject($folderId, $this->ktapi);
335 $allowed = $CMISFolder->getProperty('AllowedChildObjectTypeIds'); 309 $allowed = $CMISFolder->getProperty('AllowedChildObjectTypeIds');
336 - if (!is_array($allowed) || !in_array($typeId, $allowed))  
337 - { 310 + if (!is_array($allowed) || !in_array($typeId, $allowed)) {
338 throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')'); 311 throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')');
339 } 312 }
340 313
341 // TODO if name is blank! throw another exception (check type) - using invalidArgument Exception for now 314 // TODO if name is blank! throw another exception (check type) - using invalidArgument Exception for now
342 - if (trim($properties['name']) == '')  
343 - { 315 + if (trim($properties['name']) == '') {
344 throw new InvalidArgumentException('Refusing to create an un-named folder'); 316 throw new InvalidArgumentException('Refusing to create an un-named folder');
345 } 317 }
346 318
347 $response = $this->ktapi->create_folder((int)$folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = ''); 319 $response = $this->ktapi->create_folder((int)$folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = '');
348 - if ($response['status_code'] != 0)  
349 - { 320 + if ($response['status_code'] != 0) {
350 throw new StorageException('The repository was unable to create the folder: ' . $response['message']); 321 throw new StorageException('The repository was unable to create the folder: ' . $response['message']);
351 } 322 }
352 else 323 else
@@ -380,8 +351,7 @@ class CMISObjectService { @@ -380,8 +351,7 @@ class CMISObjectService {
380 351
381 $objectId = CMISUtil::decodeObjectId($objectId, $typeId); 352 $objectId = CMISUtil::decodeObjectId($objectId, $typeId);
382 353
383 - if ($typeId == 'Unknown')  
384 - { 354 + if ($typeId == 'Unknown') {
385 throw new ObjectNotFoundException('The type of the requested object could not be determined'); 355 throw new ObjectNotFoundException('The type of the requested object could not be determined');
386 } 356 }
387 357
@@ -492,8 +462,7 @@ class CMISObjectService { @@ -492,8 +462,7 @@ class CMISObjectService {
492 // check type id of object against allowed child types for destination folder 462 // check type id of object against allowed child types for destination folder
493 $CMISFolder = new CMISFolderObject($targetFolderId, $this->ktapi); 463 $CMISFolder = new CMISFolderObject($targetFolderId, $this->ktapi);
494 $allowed = $CMISFolder->getProperty('AllowedChildObjectTypeIds'); 464 $allowed = $CMISFolder->getProperty('AllowedChildObjectTypeIds');
495 - if (!is_array($allowed) || !in_array($typeId, $allowed))  
496 - { 465 + if (!is_array($allowed) || !in_array($typeId, $allowed)) {
497 throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')'); 466 throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')');
498 } 467 }
499 468
@@ -517,8 +486,7 @@ class CMISObjectService { @@ -517,8 +486,7 @@ class CMISObjectService {
517 } 486 }
518 487
519 // if failed, throw StorageException 488 // if failed, throw StorageException
520 - if ($response['status_code'] != 0)  
521 - { 489 + if ($response['status_code'] != 0) {
522 throw new StorageException('The repository was unable to move the object: ' . $response['message']); 490 throw new StorageException('The repository was unable to move the object: ' . $response['message']);
523 } 491 }
524 } 492 }
@@ -541,13 +509,15 @@ class CMISObjectService { @@ -541,13 +509,15 @@ class CMISObjectService {
541 // TODO this should probably be a function, it is now used in two places... 509 // TODO this should probably be a function, it is now used in two places...
542 // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). 510 // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository).
543 $exists = true; 511 $exists = true;
544 - if ($typeId == 'Folder') { 512 + if ($typeId == 'Folder')
  513 + {
545 $object = $this->ktapi->get_folder_by_id($objectId); 514 $object = $this->ktapi->get_folder_by_id($objectId);
546 if (PEAR::isError($object)) { 515 if (PEAR::isError($object)) {
547 $exists = false; 516 $exists = false;
548 } 517 }
549 } 518 }
550 - else if ($typeId == 'Document') { 519 + else if ($typeId == 'Document')
  520 + {
551 $object = $this->ktapi->get_document_by_id($objectId); 521 $object = $this->ktapi->get_document_by_id($objectId);
552 if (PEAR::isError($object)) { 522 if (PEAR::isError($object)) {
553 $exists = false; 523 $exists = false;
@@ -743,11 +713,7 @@ class CMISObjectService { @@ -743,11 +713,7 @@ class CMISObjectService {
743 throw new ContentAlreadyExistsException('Unable to overwrite existing content stream'); 713 throw new ContentAlreadyExistsException('Unable to overwrite existing content stream');
744 } 714 }
745 715
746 - // NOTE There is a function in CMISUtil to do this but since KTUploadManager exists and has more functionality  
747 - // which could come in useful at some point I decided to go with that instead (did not know it existed when  
748 - // I wrote the CMISUtil function)  
749 - $uploadManager = new KTUploadManager();  
750 - $tempfilename = $uploadManager->store_base64_file($contentStream, 'cmis_'); 716 + $tempfilename = CMISUtil::createTemporaryFile($contentStream);
751 // update the document content from this temporary file as per usual 717 // update the document content from this temporary file as per usual
752 // TODO Use checkin_document_with_metadata instead if metadata content submitted || update metadata separately? 718 // TODO Use checkin_document_with_metadata instead if metadata content submitted || update metadata separately?
753 $response = $this->ktapi->checkin_document($documentId, $csFileName, 'CMIS setContentStream action', $tempfilename, false); 719 $response = $this->ktapi->checkin_document($documentId, $csFileName, 'CMIS setContentStream action', $tempfilename, false);
lib/api/ktcmis/services/CMISVersioningService.inc.php
@@ -3,11 +3,12 @@ @@ -3,11 +3,12 @@
3 require_once(KT_DIR . '/ktapi/ktapi.inc.php'); 3 require_once(KT_DIR . '/ktapi/ktapi.inc.php');
4 require_once(CMIS_DIR . '/exceptions/ConstraintViolationException.inc.php'); 4 require_once(CMIS_DIR . '/exceptions/ConstraintViolationException.inc.php');
5 require_once(CMIS_DIR . '/exceptions/StorageException.inc.php'); 5 require_once(CMIS_DIR . '/exceptions/StorageException.inc.php');
  6 +require_once(CMIS_DIR . '/exceptions/StreamNotSupportedException.inc.php');
6 require_once(CMIS_DIR . '/exceptions/UpdateConflictException.inc.php'); 7 require_once(CMIS_DIR . '/exceptions/UpdateConflictException.inc.php');
7 require_once(CMIS_DIR . '/exceptions/VersioningException.inc.php'); 8 require_once(CMIS_DIR . '/exceptions/VersioningException.inc.php');
8 require_once(CMIS_DIR . '/services/CMISObjectService.inc.php'); 9 require_once(CMIS_DIR . '/services/CMISObjectService.inc.php');
9 require_once(CMIS_DIR . '/objecttypes/CMISDocumentObject.inc.php'); 10 require_once(CMIS_DIR . '/objecttypes/CMISDocumentObject.inc.php');
10 -//require_once(CMIS_DIR . '/util/CMISUtil.inc.php'); 11 +require_once(CMIS_DIR . '/util/CMISUtil.inc.php');
11 12
12 class CMISVersioningService { 13 class CMISVersioningService {
13 14
@@ -182,14 +183,8 @@ class CMISVersioningService { @@ -182,14 +183,8 @@ class CMISVersioningService {
182 * @return string $documentId 183 * @return string $documentId
183 */ 184 */
184 // TODO Exceptions: 185 // TODO Exceptions:
185 - // โ€ข ConstraintViolationException - SHALL throw if o The Documentโ€™s Object-Type definitionโ€™s versionable attribute is FALSE.  
186 - // โ€ข storageException - MAY throw  
187 - // โ€ข streamNotSupportedException - The Repository SHALL throw this exception if the Object-Type definition specified by the typeId  
188 - // parameterโ€™s โ€œcontentStreamAllowedโ€ attribute is set to โ€œnot allowedโ€ and a contentStream input  
189 - // parameter is provided.  
190 - // โ€ข updateConflictException - MAY throw  
191 // โ€ข versioningException - The repository MAY throw this exception if the object is a non-current Document Version 186 // โ€ข versioningException - The repository MAY throw this exception if the object is a non-current Document Version
192 - public function checkIn($repositoryId, $documentId, $major, $changeToken = '', $properties = array(), $contentStream = null, $checkinComment = '') 187 + public function checkIn($repositoryId, $documentId, $major, $contentStream = null, $changeToken = '', $properties = array(), $checkinComment = '')
193 { 188 {
194 $documentId = CMISUtil::decodeObjectId($documentId, $typeId); 189 $documentId = CMISUtil::decodeObjectId($documentId, $typeId);
195 190
@@ -206,7 +201,35 @@ class CMISVersioningService { @@ -206,7 +201,35 @@ class CMISVersioningService {
206 throw new ConstraintViolationException('This document is not versionable and may not be checked in'); 201 throw new ConstraintViolationException('This document is not versionable and may not be checked in');
207 } 202 }
208 203
209 - return $documentId; 204 + $RepositoryService = new CMISRepositoryService();
  205 + try {
  206 + $typeDefinition = $RepositoryService->getTypeDefinition($repositoryId, $typeId);
  207 + }
  208 + catch (exception $e) {
  209 + // if we can't get the type definition, then we can't store the content
  210 + throw new StorageException($e->getMessage());
  211 + }
  212 +
  213 + if (($typeDefinition['attributes']['contentStreamAllowed'] == 'notAllowed') && !empty($contentStream)) {
  214 + throw new StreamNotSupportedException('Content Streams are not supported');
  215 + }
  216 +
  217 + // check that this is the latest version
  218 + if ($pwc->getProperty('IsLatestVersion') != true) {
  219 + throw new VersioningException('The document is not the latest version and cannot be checked in');
  220 + }
  221 +
  222 + // now do the checkin
  223 + $tempfilename = CMISUtil::createTemporaryFile($contentStream);
  224 + $response = $this->ktapi->checkin_document($documentId, $pwc->getProperty('ContentStreamFilename'), $reason, $tempfilename, $major,
  225 + $sig_username, $sig_password);
  226 +
  227 + // if there was any error in cancelling the checkout
  228 + if ($response['status_code'] == 1) {
  229 + throw new RuntimeException('There was an error checking in the document: ' . $response['message']);
  230 + }
  231 +
  232 + return CMISUtil::encodeObjectId(DOCUMENT, $documentId);
210 } 233 }
211 234
212 } 235 }
lib/api/ktcmis/util/CMISUtil.inc.php
@@ -406,30 +406,6 @@ class CMISUtil { @@ -406,30 +406,6 @@ class CMISUtil {
406 return (($input === true) ? 'true' : (($input === false) ? 'false' : $input)); 406 return (($input === true) ? 'true' : (($input === false) ? 'false' : $input));
407 } 407 }
408 408
409 - /**  
410 - * Creates a temporary file  
411 - * Cleanup is the responsibility of the calling code  
412 - *  
413 - * @param string|binary $content The content to be written to the file.  
414 - * @param string $uploadDir Optional upload directory. Will use the KnowledgeTree system tmp directory if not supplied.  
415 - * @return string The path to the created file (for reference and cleanup.)  
416 - */  
417 - static public function createTemporaryFile($content, $encoding = null, $uploadDir = null)  
418 - {  
419 - if(is_null($uploadDir))  
420 - {  
421 - $oKTConfig =& KTConfig::getSingleton();  
422 - $uploadDir = $oKTConfig->get('webservice/uploadDirectory');  
423 - }  
424 -  
425 - $temp = tempnam($uploadDir, 'myfile');  
426 - $fp = fopen($temp, 'wb');  
427 - fwrite($fp, ($encoding == 'base64' ? base64_decode($content) : $content));  
428 - fclose($fp);  
429 -  
430 - return $temp;  
431 - }  
432 -  
433 // TODO more robust base64 encoding detection, if possible 409 // TODO more robust base64 encoding detection, if possible
434 410
435 /** 411 /**
@@ -610,6 +586,33 @@ class CMISUtil { @@ -610,6 +586,33 @@ class CMISUtil {
610 586
611 return $exists; 587 return $exists;
612 } 588 }
  589 +
  590 + /**
  591 + * Creates a temporary file
  592 + * Cleanup is the responsibility of the calling code
  593 + *
  594 + * @param string $contentStream The content to be stored (assumed to be base64)
  595 + * @return string The path to the created file (for reference and cleanup.)
  596 + */
  597 + static public function createTemporaryFile($contentStream)
  598 + {
  599 + // if contentStream is empty, cannot create file
  600 + if (empty($contentStream)) return null;
  601 +
  602 + // TODO consider checking whether content is encoded (currently we expect encoded)
  603 + // TODO choose between this and the alternative decode function (see CMISUtil class)
  604 + // this will require some basic benchmarking
  605 + $contentStream = CMISUtil::decodeChunkedContentStream($contentStream);
  606 +
  607 + // NOTE There is a function in CMISUtil to do this, written for the unit tests but since KTUploadManager exists
  608 + // and has more functionality which could come in useful at some point I decided to go with that instead
  609 + // (did not know this existed when I wrote the CMISUtil function)
  610 + $uploadManager = new KTUploadManager();
  611 + // assumes already decoded from base64, should use store_base64_file if not
  612 + $tempfilename = $uploadManager->store_file($contentStream, 'cmis_');
  613 +
  614 + return $tempfilename;
  615 + }
613 616
614 } 617 }
615 618
plugins/thumbnails/templates/thumbnail_viewlet.smarty 0 โ†’ 100644
plugins/thumbnails/thumbnails.php 0 โ†’ 100644
  1 +<?php
  2 +/*
  3 + * $Id: $
  4 + *
  5 + * The contents of this file are subject to the KnowledgeTree
  6 + * Commercial Editions On-Premise License ("License");
  7 + * You may not use this file except in compliance with the License.
  8 + * You may obtain a copy of the License at
  9 + * http://www.knowledgetree.com/about/legal/
  10 + * The terms of this license may change from time to time and the latest
  11 + * license will be published from time to time at the above Internet address.
  12 + *
  13 + * This edition of the KnowledgeTree software
  14 + * is NOT licensed to you under Open Source terms.
  15 + * You may not redistribute this source code.
  16 + * For more information please see the License above.
  17 + *
  18 + * (c) 2008 KnowledgeTree Inc.
  19 + * Portions copyright The Jam Warehouse Software (Pty) Ltd;
  20 + * All Rights Reserved.
  21 + *
  22 + */
  23 +
  24 +require_once(KT_LIB_DIR . "/actions/documentviewlet.inc.php");
  25 +require_once(KT_DIR . '/search2/documentProcessor/documentProcessor.inc.php');
  26 +
  27 +/**
  28 + * Generates thumbnails of documents using the pdf converter output
  29 + * Dependent on the pdfConverter
  30 + */
  31 +class thumbnailGenerator extends BaseProcessor
  32 +{
  33 + public $order = 3;
  34 + protected $namespace = 'thumbnails.generator.processor';
  35 +
  36 + /**
  37 + * Constructor
  38 + *
  39 + * @return thumbnailGenerator
  40 + */
  41 + public function thumbnailGenerator()
  42 + {
  43 + }
  44 +
  45 + /**
  46 + * Gets the document path and calls the generator function
  47 + *
  48 + * @return boolean
  49 + */
  50 + public function processDocument()
  51 + {
  52 + // do the generation
  53 + $res = $this->generateThumbnail();
  54 + return $res;
  55 + }
  56 +
  57 + /**
  58 + * The supported mime types for the converter.
  59 + *
  60 + * @return array
  61 + */
  62 + public function getSupportedMimeTypes()
  63 + {
  64 +// $aAcceptedMimeTypes = array('doc', 'ods', 'odt', 'ott', 'txt', 'rtf', 'sxw', 'stw',
  65 +// // 'html', 'htm',
  66 +// 'xml' , 'pdb', 'psw', 'ods', 'ots', 'sxc',
  67 +// 'stc', 'dif', 'dbf', 'xls', 'xlt', 'slk', 'csv', 'pxl',
  68 +// 'odp', 'otp', 'sxi', 'sti', 'ppt', 'pot', 'sxd', 'odg',
  69 +// 'otg', 'std', 'asc');
  70 +
  71 + // taken from the original list of accepted types in the pdf generator action
  72 + $mime_types = array();
  73 + $mime_types[] = 'text/plain';
  74 + $mime_types[] = 'text/html';
  75 + $mime_types[] = 'text/csv';
  76 + $mime_types[] = 'text/rtf';
  77 +
  78 + // Office OLE2 - 2003, XP, etc
  79 + $mime_types[] = 'application/msword';
  80 + $mime_types[] = 'application/vnd.ms-powerpoint';
  81 + $mime_types[] = 'application/vnd.ms-excel';
  82 +
  83 + // Star Office
  84 + $mime_types[] = 'application/vnd.sun.xml.writer';
  85 + $mime_types[] = 'application/vnd.sun.xml.writer.template';
  86 + $mime_types[] = 'application/vnd.sun.xml.calc';
  87 + $mime_types[] = 'application/vnd.sun.xml.calc.template';
  88 + $mime_types[] = 'application/vnd.sun.xml.draw';
  89 + $mime_types[] = 'application/vnd.sun.xml.draw.template';
  90 + $mime_types[] = 'application/vnd.sun.xml.impress';
  91 + $mime_types[] = 'application/vnd.sun.xml.impress.template';
  92 +
  93 + // Open Office
  94 + $mime_types[] = 'application/vnd.oasis.opendocument.text';
  95 + $mime_types[] = 'application/vnd.oasis.opendocument.text-template';
  96 + $mime_types[] = 'application/vnd.oasis.opendocument.graphics';
  97 + $mime_types[] = 'application/vnd.oasis.opendocument.graphics-template';
  98 + $mime_types[] = 'application/vnd.oasis.opendocument.presentation';
  99 + $mime_types[] = 'application/vnd.oasis.opendocument.presentation-template';
  100 + $mime_types[] = 'application/vnd.oasis.opendocument.spreadsheet';
  101 + $mime_types[] = 'application/vnd.oasis.opendocument.spreadsheet-template';
  102 +
  103 + /* OO3
  104 + // Office 2007
  105 + $mime_types[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
  106 + $mime_types[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.template';
  107 + $mime_types[] = 'application/vnd.openxmlformats-officedocument.presentationml.template';
  108 + $mime_types[] = 'application/vnd.openxmlformats-officedocument.presentationml.slideshow';
  109 + $mime_types[] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
  110 + $mime_types[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
  111 + $mime_types[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.template';
  112 + */
  113 +
  114 + return $mime_types;
  115 + }
  116 +
  117 + /**
  118 + * Generates the thumbnail from the pdf
  119 + *
  120 + * @return boolean
  121 + */
  122 + private function generateThumbnail()
  123 + {
  124 + /*
  125 + The thumbnail is displayed in the info panel and the document view
  126 + The info panel is in the plugin ktcore/documentpreview/
  127 + - add a hook in there but build the functionality in this plugin ie keep the plugins separate and don't create dependencies
  128 + - if the thumbnail plugin is disabled then maybe display a normal sized info panel
  129 +
  130 + The document view will display the thumbnail on the right in a document viewlet similar to the workflow viewlet
  131 + - check out ktcore/KTDocumentViewlets.php
  132 + - viewlet class is below
  133 + */
  134 +
  135 + $pdfDir = $default->pdfDirectory;
  136 + $pdfFile = $pdfDir .'/'. $this->document->iId.'.pdf';
  137 +
  138 + // if a previous version of the pdf exists - delete it
  139 + if(!file_exists($pdfFile)){
  140 + global $default;
  141 + $default->log->debug('Thumbnail Generator Plugin: PDF file does not exist, cannot generate a thumbnail');
  142 + return false;
  143 + }
  144 +
  145 + // do generation
  146 + return true;
  147 + }
  148 +}
  149 +
  150 +
  151 +class ThumbnailViewlet extends KTDocumentViewlet {
  152 + var $sName = 'thumbnail.viewlets';
  153 +
  154 + function display_viewlet() {
  155 + $oKTTemplating =& KTTemplating::getSingleton();
  156 + $oTemplate =& $oKTTemplating->loadTemplate('thumbnail_viewlet');
  157 + if (is_null($oTemplate)) return '';
  158 +
  159 + $oTemplate->setData(array());
  160 + return $oTemplate->render();
  161 + }
  162 +}
  163 +
  164 +?>
0 \ No newline at end of file 165 \ No newline at end of file
plugins/thumbnails/thumbnailsPlugin.php 0 โ†’ 100644
  1 +<?php
  2 +/**
  3 + * $Id: $
  4 + *
  5 + * The contents of this file are subject to the KnowledgeTree
  6 + * Commercial Editions On-Premise License ("License");
  7 + * You may not use this file except in compliance with the License.
  8 + * You may obtain a copy of the License at
  9 + * http://www.knowledgetree.com/about/legal/
  10 + * The terms of this license may change from time to time and the latest
  11 + * license will be published from time to time at the above Internet address.
  12 + *
  13 + * This edition of the KnowledgeTree software
  14 + * is NOT licensed to you under Open Source terms.
  15 + * You may not redistribute this source code.
  16 + * For more information please see the License above.
  17 + *
  18 + * (c) 2008 KnowledgeTree Inc.
  19 + * Portions copyright The Jam Warehouse Software (Pty) Ltd;
  20 + * All Rights Reserved.
  21 + *
  22 + */
  23 +
  24 +require_once(KT_LIB_DIR . '/plugins/plugin.inc.php');
  25 +require_once(KT_LIB_DIR . '/plugins/pluginregistry.inc.php');
  26 +
  27 +class thumbnailsPlugin extends KTPlugin {
  28 + var $sNamespace = 'thumbnails.generator.processor.plugin';
  29 + var $iVersion = 0;
  30 + var $autoRegister = true;
  31 +
  32 + function thumbnailsPlugin($sFilename = null) {
  33 + $res = parent::KTPlugin($sFilename);
  34 + $this->sFriendlyName = _kt('Thumbnail Generator');
  35 + return $res;
  36 + }
  37 +
  38 + /**
  39 + * Setup the plugin: add the processor, viewlet action and template location
  40 + *
  41 + */
  42 + function setup() {
  43 + $plugin_dir = dirname(__FILE__) . DIRECTORY_SEPARATOR;
  44 + $dir = $plugin_dir . 'thumbnails.php';
  45 + $this->registerProcessor('thumbnailGenerator', 'thumbnails.generator.processor', $dir);
  46 + $this->registerAction('documentviewlet', 'ThumbnailViewlet', 'thumbnail.viewlets', $dir);
  47 +
  48 + require_once(KT_LIB_DIR . '/templating/templating.inc.php');
  49 + $oTemplating =& KTTemplating::getSingleton();
  50 + $oTemplating->addLocation('thumbnails', $plugin_dir.'templates', 'thumbnails.generator.processor.plugin');
  51 + }
  52 +}
  53 +
  54 +$oPluginRegistry =& KTPluginRegistry::getSingleton();
  55 +$oPluginRegistry->registerPlugin('thumbnailsPlugin', 'thumbnails.generator.processor.plugin', __FILE__);
  56 +?>
0 \ No newline at end of file 57 \ No newline at end of file
var/Documents/.cvsignore deleted
1 -Deleted  
2 -.cvsignore  
var/log/.cvsignore deleted
1 -*  
var/tmp/.cvsignore deleted
1 -*  
webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php
@@ -101,7 +101,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { @@ -101,7 +101,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
101 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $folderId); 101 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $folderId);
102 } 102 }
103 103
104 - //Expose the responseFeed 104 + // Expose the responseFeed
105 $this->responseFeed = $feed; 105 $this->responseFeed = $feed;
106 } 106 }
107 107
@@ -140,7 +140,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { @@ -140,7 +140,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
140 $objectId = $this->params[2]; 140 $objectId = $this->params[2];
141 } 141 }
142 142
143 - $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->parsedXMLContent['@children']['cmis:object']); 143 + $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->parsedXMLContent['@children']);
144 144
145 // check for existing object id as property of submitted object data 145 // check for existing object id as property of submitted object data
146 if (!empty($cmisObjectProperties['ObjectId'])) 146 if (!empty($cmisObjectProperties['ObjectId']))
@@ -159,7 +159,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { @@ -159,7 +159,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
159 CMISUtil::decodeObjectId($objectId, $typeId); 159 CMISUtil::decodeObjectId($objectId, $typeId);
160 } 160 }
161 161
162 - // now check for content stream 162 + // check for content stream
163 $content = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'content'); 163 $content = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'content');
164 164
165 // TODO this will possibly need to change somewhat once Relationship Objects come into play. 165 // TODO this will possibly need to change somewhat once Relationship Objects come into play.
@@ -207,7 +207,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { @@ -207,7 +207,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
207 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $error); 207 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $error);
208 } 208 }
209 209
210 - //Expose the responseFeed 210 + // Expose the responseFeed
211 $this->responseFeed = $feed; 211 $this->responseFeed = $feed;
212 } 212 }
213 213
@@ -236,7 +236,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { @@ -236,7 +236,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
236 if (PEAR::isError($response)) 236 if (PEAR::isError($response))
237 { 237 {
238 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage()); 238 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage());
239 - //Expose the responseFeed 239 + // Expose the responseFeed
240 $this->responseFeed = $feed; 240 $this->responseFeed = $feed;
241 return null; 241 return null;
242 } 242 }
@@ -349,7 +349,7 @@ class KT_cmis_atom_service_types extends KT_cmis_atom_service { @@ -349,7 +349,7 @@ class KT_cmis_atom_service_types extends KT_cmis_atom_service {
349 $type = ((empty($this->params[0])) ? 'all' : $this->params[0]); 349 $type = ((empty($this->params[0])) ? 'all' : $this->params[0]);
350 $feed = KT_cmis_atom_service_helper::getTypeFeed($type, $types); 350 $feed = KT_cmis_atom_service_helper::getTypeFeed($type, $types);
351 351
352 - //Expose the responseFeed 352 + // Expose the responseFeed
353 $this->responseFeed = $feed; 353 $this->responseFeed = $feed;
354 } 354 }
355 355
@@ -385,7 +385,7 @@ class KT_cmis_atom_service_type extends KT_cmis_atom_service { @@ -385,7 +385,7 @@ class KT_cmis_atom_service_type extends KT_cmis_atom_service {
385 $feed = $this->getTypeChildrenFeed($this->params[1]); 385 $feed = $this->getTypeChildrenFeed($this->params[1]);
386 } 386 }
387 387
388 - //Expose the responseFeed 388 + // Expose the responseFeed
389 $this->responseFeed=$feed; 389 $this->responseFeed=$feed;
390 } 390 }
391 391
@@ -494,7 +494,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { @@ -494,7 +494,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
494 // $entry = null; 494 // $entry = null;
495 // $feed->newField('cmis:hasMoreItems', 'false', $entry, true); 495 // $feed->newField('cmis:hasMoreItems', 'false', $entry, true);
496 496
497 - //Expose the responseFeed 497 + // Expose the responseFeed
498 $this->responseFeed = $feed; 498 $this->responseFeed = $feed;
499 } 499 }
500 500
@@ -513,7 +513,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { @@ -513,7 +513,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
513 if (empty($cmisObjectProperties['ObjectId'])) 513 if (empty($cmisObjectProperties['ObjectId']))
514 { 514 {
515 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, 'No object was specified for checkout'); 515 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, 'No object was specified for checkout');
516 - //Expose the responseFeed 516 + // Expose the responseFeed
517 $this->responseFeed = $feed; 517 $this->responseFeed = $feed;
518 return null; 518 return null;
519 } 519 }
@@ -523,7 +523,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { @@ -523,7 +523,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
523 if (PEAR::isError($response)) 523 if (PEAR::isError($response))
524 { 524 {
525 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, 'No object was specified for checkout'); 525 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, 'No object was specified for checkout');
526 - //Expose the responseFeed 526 + // Expose the responseFeed
527 $this->responseFeed = $feed; 527 $this->responseFeed = $feed;
528 return null; 528 return null;
529 } 529 }
@@ -531,7 +531,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { @@ -531,7 +531,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
531 $this->setStatus(self::STATUS_CREATED); 531 $this->setStatus(self::STATUS_CREATED);
532 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $cmisObjectProperties['ObjectId'], 'POST'); 532 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $cmisObjectProperties['ObjectId'], 'POST');
533 533
534 - //Expose the responseFeed 534 + // Expose the responseFeed
535 $this->responseFeed = $feed; 535 $this->responseFeed = $feed;
536 } 536 }
537 537
@@ -559,13 +559,13 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service { @@ -559,13 +559,13 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service {
559 // this depends on $this->params[1] 559 // this depends on $this->params[1]
560 if (!empty($this->params[1])) 560 if (!empty($this->params[1]))
561 { 561 {
562 - $this->getContentStream($ObjectService, $repositoryId); 562 + KT_cmis_atom_service_helper::downloadContentStream($this, $ObjectService, $repositoryId);
563 return null; 563 return null;
564 } 564 }
565 565
566 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $this->params[0]); 566 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $this->params[0]);
567 567
568 - //Expose the responseFeed 568 + // Expose the responseFeed
569 $this->responseFeed = $feed; 569 $this->responseFeed = $feed;
570 } 570 }
571 571
@@ -594,7 +594,7 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service { @@ -594,7 +594,7 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service {
594 if (PEAR::isError($response)) 594 if (PEAR::isError($response))
595 { 595 {
596 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage()); 596 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage());
597 - //Expose the responseFeed 597 + // Expose the responseFeed
598 $this->responseFeed = $feed; 598 $this->responseFeed = $feed;
599 return null; 599 return null;
600 } 600 }
@@ -603,46 +603,6 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service { @@ -603,46 +603,6 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service {
603 $this->setStatus(self::STATUS_NO_CONTENT); 603 $this->setStatus(self::STATUS_NO_CONTENT);
604 } 604 }
605 605
606 - private function getContentStream(&$ObjectService, $repositoryId)  
607 - {  
608 - $response = $ObjectService->getProperties($repositoryId, $this->params[0], false, false);  
609 - if (PEAR::isError($response)) {  
610 - $feed = KT_cmis_atom_service_helper::getErrorFeed($this, KT_cmis_atom_service::STATUS_SERVER_ERROR, $response->getMessage());  
611 - $this->responseFeed = $feed;  
612 - return null;  
613 - }  
614 -  
615 - // TODO also check If-Modified-Since?  
616 -// $this->headers['If-Modified-Since'] => 2009-07-24 17:16:54  
617 -  
618 - $this->contentDownload = true;  
619 - $eTag = md5($response['properties']['LastModificationDate']['value'] . $response['properties']['ContentStreamLength']['value']);  
620 -  
621 - if ($this->headers['If-None-Match'] == $eTag)  
622 - {  
623 - $this->setStatus(self::STATUS_NOT_MODIFIED);  
624 - $this->contentDownload = false;  
625 - return null;  
626 - }  
627 -  
628 - $contentStream = $ObjectService->getContentStream($repositoryId, $this->params[0]);  
629 -  
630 - // headers specific to output  
631 - $this->setEtag($eTag);  
632 - $this->setHeader('Last-Modified', $response['properties']['LastModificationDate']['value']);  
633 -  
634 - if (!empty($response['properties']['ContentStreamMimeType']['value'])) {  
635 - $this->setHeader('Content-type', $response['properties']['ContentStreamMimeType']['value'] . ';charset=utf-8');  
636 - }  
637 - else {  
638 - $this->setHeader('Content-type', 'text/plain;charset=utf-8');  
639 - }  
640 -  
641 - $this->setHeader('Content-Disposition', 'attachment;filename="' . $response['properties']['ContentStreamFilename']['value'] . '"');  
642 - $this->setHeader('Content-Length', $response['properties']['ContentStreamLength']['value']);  
643 - $this->output = $contentStream;  
644 - }  
645 -  
646 } 606 }
647 607
648 class KT_cmis_atom_service_pwc extends KT_cmis_atom_service { 608 class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
@@ -665,13 +625,13 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service { @@ -665,13 +625,13 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
665 // this depends on $this->params[1] 625 // this depends on $this->params[1]
666 if (!empty($this->params[1])) 626 if (!empty($this->params[1]))
667 { 627 {
668 - $this->getContentStream($ObjectService, $repositoryId); 628 + KT_cmis_atom_service_helper::downloadContentStream($this, $ObjectService, $repositoryId);
669 return null; 629 return null;
670 } 630 }
671 631
672 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $this->params[0]); 632 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $this->params[0]);
673 633
674 - //Expose the responseFeed 634 + // Expose the responseFeed
675 $this->responseFeed = $feed; 635 $this->responseFeed = $feed;
676 } 636 }
677 637
@@ -696,7 +656,7 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service { @@ -696,7 +656,7 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
696 if (PEAR::isError($response)) 656 if (PEAR::isError($response))
697 { 657 {
698 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage()); 658 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage());
699 - //Expose the responseFeed 659 + // Expose the responseFeed
700 $this->responseFeed = $feed; 660 $this->responseFeed = $feed;
701 return null; 661 return null;
702 } 662 }
@@ -714,18 +674,52 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service { @@ -714,18 +674,52 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
714 $repositories = $RepositoryService->getRepositories(); 674 $repositories = $RepositoryService->getRepositories();
715 $repositoryId = $repositories[0]['repositoryId']; 675 $repositoryId = $repositories[0]['repositoryId'];
716 676
717 - $response = $VersioningService->checkIn($repositoryId, $this->params[0]); 677 + // check for content stream
  678 + // NOTE this is a hack! will not work with CMISSpaces at least, probably not with any client except RestTest and similar
  679 + // where we can manually modify the input
  680 + // first we try for an atom content tag
  681 + $content = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'content');
  682 + if (!empty($content)) {
  683 + $contentStream = $content;
  684 + }
  685 + // not found? try for a regular content tag
  686 + else {
  687 + $content = KT_cmis_atom_service_helper::findTag('content', $this->parsedXMLContent['@children'], null, false);
  688 + $contentStream = $content['@value'];
  689 + }
  690 +
  691 + // if we haven't found it now, the real hack begins - retrieve the EXISTING content and submit this as the contentStream
  692 + // this is needed because KnowledgeTree will not accept a checkin without a content stream but CMISSpaces (and possibly
  693 + // other CMIS clients are the same, does not send a content stream on checkin nor does it offer the user a method to choose one)
  694 + // NOTE that if the content is INTENDED to be empty this and all the above checks will FAIL!
  695 + // FIXME this is horrible, terrible, ugly and bad!
  696 + if (empty($contentStream))
  697 + {
  698 + $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt());
  699 + $contentStream = base64_encode(KT_cmis_atom_service_helper::getContentStream($this, $ObjectService, $repositoryId));
  700 + }
  701 +
  702 + // and if we don't have it by now, we give up...but leave the error to be generated by the underlying KnowledgeTree code
  703 +
  704 + // checkin function call
  705 + // TODO dynamically detect version change type - leaving this for now as the CMIS clients tested do not appear to
  706 + // offer the choice to the user - perhaps it will turn out that this will come from somewhere else but for now
  707 + // we assume minor version updates only
  708 + $major = false;
  709 + $response = $VersioningService->checkIn($repositoryId, $this->params[0], $major, $contentStream);
718 710
719 if (PEAR::isError($response)) 711 if (PEAR::isError($response))
720 { 712 {
721 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage()); 713 $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage());
722 - //Expose the responseFeed 714 + // Expose the responseFeed
723 $this->responseFeed = $feed; 715 $this->responseFeed = $feed;
724 return null; 716 return null;
725 } 717 }
726 718
727 - $this->setStatus(self::STATUS_NO_CONTENT);  
728 - $this->responseFeed = null; 719 + $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $this->params[0]);
  720 +
  721 + // Expose the responseFeed
  722 + $this->responseFeed = $feed;
729 } 723 }
730 724
731 } 725 }
webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php
@@ -418,7 +418,7 @@ class KT_cmis_atom_service_helper { @@ -418,7 +418,7 @@ class KT_cmis_atom_service_helper {
418 while($start < $numFolders) 418 while($start < $numFolders)
419 { 419 {
420 $name = $path[$numQ-$numFolders+$start]; 420 $name = $path[$numQ-$numFolders+$start];
421 - // hack to fix drupal url encoding issue 421 + // fix for possible url encoding issue
422 $name = str_replace('%2520', '%20', $name); 422 $name = str_replace('%2520', '%20', $name);
423 423
424 $folderName = urldecode($name); 424 $folderName = urldecode($name);
@@ -494,6 +494,71 @@ class KT_cmis_atom_service_helper { @@ -494,6 +494,71 @@ class KT_cmis_atom_service_helper {
494 return date('Y-m-d H:i:s', $time); 494 return date('Y-m-d H:i:s', $time);
495 } 495 }
496 496
  497 + /**
  498 + * Fetches the document content stream for internal use
  499 + *
  500 + * @param object $ObjectService
  501 + * @param string $repositoryId
  502 + * @return null | string $contentStream
  503 + */
  504 + static public function getContentStream(&$service, &$ObjectService, $repositoryId)
  505 + {
  506 + $response = $ObjectService->getProperties($repositoryId, $service->params[0], false, false);
  507 + if (PEAR::isError($response)) {
  508 + return null;
  509 + }
  510 +
  511 + $contentStream = $ObjectService->getContentStream($repositoryId, $service->params[0]);
  512 +
  513 + return $contentStream;
  514 + }
  515 + /**
  516 + * Fetches and prepares the document content stream for download/viewing
  517 + *
  518 + * @param object $ObjectService
  519 + * @param string $repositoryId
  520 + * @return null | nothing
  521 + */
  522 + static public function downloadContentStream(&$service, &$ObjectService, $repositoryId)
  523 + {
  524 + $response = $ObjectService->getProperties($repositoryId, $service->params[0], false, false);
  525 + if (PEAR::isError($response)) {
  526 + $feed = KT_cmis_atom_service_helper::getErrorFeed($service, KT_cmis_atom_service::STATUS_SERVER_ERROR, $response->getMessage());
  527 + $service->responseFeed = $feed;
  528 + return null;
  529 + }
  530 +
  531 + // TODO also check If-Modified-Since?
  532 +// $service->headers['If-Modified-Since'] => 2009-07-24 17:16:54
  533 +
  534 + $service->setContentDownload(true);
  535 + $eTag = md5($response['properties']['LastModificationDate']['value'] . $response['properties']['ContentStreamLength']['value']);
  536 +
  537 + if ($service->headers['If-None-Match'] == $eTag)
  538 + {
  539 + $service->setStatus(KT_cmis_atom_service::STATUS_NOT_MODIFIED);
  540 + $service->setContentDownload(false);
  541 + return null;
  542 + }
  543 +
  544 + $contentStream = $ObjectService->getContentStream($repositoryId, $service->params[0]);
  545 +
  546 + // headers specific to output
  547 + $service->setEtag($eTag);
  548 + $service->setHeader('Last-Modified', $response['properties']['LastModificationDate']['value']);
  549 +
  550 + if (!empty($response['properties']['ContentStreamMimeType']['value'])) {
  551 + $service->setHeader('Content-type', $response['properties']['ContentStreamMimeType']['value'] . ';charset=utf-8');
  552 + }
  553 + else {
  554 + $service->setHeader('Content-type', 'text/plain;charset=utf-8');
  555 + }
  556 +
  557 + $service->setHeader('Content-Disposition', 'attachment;filename="' . $response['properties']['ContentStreamFilename']['value'] . '"');
  558 + $service->setHeader('Content-Length', $response['properties']['ContentStreamLength']['value']);
  559 + $service->setOutput($contentStream);
  560 + }
  561 +
497 //TODO: Add key information to be able to find the same tag in the original struct (MarkH) 562 //TODO: Add key information to be able to find the same tag in the original struct (MarkH)
498 static public function findTag($tagName=NULL,$xml=array(),$tagArray=NULL,$deep=false){ 563 static public function findTag($tagName=NULL,$xml=array(),$tagArray=NULL,$deep=false){
499 $tagArray=is_array($tagArray)?$tagArray:array(); 564 $tagArray=is_array($tagArray)?$tagArray:array();
webservice/classes/atompub/KT_atom_service.inc.php
@@ -147,7 +147,7 @@ class KT_atom_service{ @@ -147,7 +147,7 @@ class KT_atom_service{
147 header("HTTP/1.1 ".$status); 147 header("HTTP/1.1 ".$status);
148 } 148 }
149 149
150 - protected function setEtag($etagValue=NULL){ 150 + public function setEtag($etagValue=NULL){
151 if($etagValue)header('ETag: '.$etagValue); 151 if($etagValue)header('ETag: '.$etagValue);
152 } 152 }
153 153
webservice/classes/atompub/cmis/KT_cmis_atom_service.inc.php
@@ -8,7 +8,12 @@ class KT_cmis_atom_service extends KT_atom_service { @@ -8,7 +8,12 @@ class KT_cmis_atom_service extends KT_atom_service {
8 8
9 protected $serviceType = null; 9 protected $serviceType = null;
10 protected $contentDownload = false; 10 protected $contentDownload = false;
11 - 11 +
  12 + public function setContentDownload($contentDownload)
  13 + {
  14 + $this->contentDownload = $contentDownload;
  15 + }
  16 +
12 public public function isContentDownload() 17 public public function isContentDownload()
13 { 18 {
14 return $this->contentDownload; 19 return $this->contentDownload;
@@ -19,6 +24,11 @@ class KT_cmis_atom_service extends KT_atom_service { @@ -19,6 +24,11 @@ class KT_cmis_atom_service extends KT_atom_service {
19 return $this->status == self::STATUS_NOT_MODIFIED; 24 return $this->status == self::STATUS_NOT_MODIFIED;
20 } 25 }
21 26
  27 + public function setoutput($output)
  28 + {
  29 + $this->output = $output;
  30 + }
  31 +
22 public function getOutput() 32 public function getOutput()
23 { 33 {
24 return $this->output; 34 return $this->output;
@@ -29,7 +39,7 @@ class KT_cmis_atom_service extends KT_atom_service { @@ -29,7 +39,7 @@ class KT_cmis_atom_service extends KT_atom_service {
29 return $this->serviceType; 39 return $this->serviceType;
30 } 40 }
31 41
32 - protected function setHeader($header = null, $value = null) 42 + public function setHeader($header = null, $value = null)
33 { 43 {
34 if ($header) header($header . ': ' . $value); 44 if ($header) header($header . ': ' . $value);
35 } 45 }
webservice/classes/atompub/cmis/VersioningService.inc.php
@@ -85,9 +85,9 @@ class VersioningService extends KTVersioningService { @@ -85,9 +85,9 @@ class VersioningService extends KTVersioningService {
85 * @param string $checkinComment [optional] 85 * @param string $checkinComment [optional]
86 * @return string $documentId 86 * @return string $documentId
87 */ 87 */
88 - public function checkIn($repositoryId, $documentId, $major, $changeToken = '', $properties = array(), $contentStream = null, $checkinComment = '') 88 + public function checkIn($repositoryId, $documentId, $major, $contentStream = null, $changeToken = '', $properties = array(), $checkinComment = '')
89 { 89 {
90 - $result = parent::checkIn($repositoryId, $documentId, $major, $changeToken, $properties, $contentStream, $checkinComment); 90 + $result = parent::checkIn($repositoryId, $documentId, $major, $contentStream, $changeToken, $properties, $checkinComment);
91 91
92 if ($result['status_code'] == 0) { 92 if ($result['status_code'] == 0) {
93 return $result['results']; 93 return $result['results'];