Commit 1f10b1709cd50df4a45d89facbe0c4e53a2b3653

Authored by Paul Barrett
1 parent 9f69bab5

Added AtomPub level implementation for checkout related functions

Story ID:1093055. CMIS Checkout

In Progress

Committed by: Paul Barrett

Reviewed by: Jarrett Jordaan
ktapi/ktapi.inc.php
... ... @@ -3254,6 +3254,8 @@ class KTAPI
3254 3254 * @param boolean $userSpecific limit to current user
3255 3255 * @return $checkedout An array of checked out documents
3256 3256 */
  3257 + // TODO determine whether the listing is showing docs the user should not be able to see
  3258 + // (when not restricting to docs checked out by that user)
3257 3259 public function get_checkedout_docs($userSpecific = true)
3258 3260 {
3259 3261 $checkedout = array();
... ...
lib/api/ktcmis/classes/CMISDocumentPropertyCollection.inc.php
... ... @@ -66,6 +66,14 @@ class CMISDocumentPropertyCollection extends CMISPropertyCollection {
66 66 function __construct()
67 67 {
68 68 parent::__construct();
  69 + self::$propertyTypes = array_merge(self::$propertyTypes, array('ContentStreamAllowed' => 'propertyString',
  70 + 'ContentStreamLength' => 'propertyInteger',
  71 + 'ContentStreamMimeType' => 'propertyString',
  72 + 'ContentStreamFilename' => 'propertyString',
  73 + 'ContentStreamUri' => 'propertyUri',
  74 + 'IsVersionSeriesCheckedOut' => 'propertyBoolean',
  75 + 'VersionSeriesCheckedOutBy' => 'propertyString',
  76 + 'VersionSeriesCheckedOutId' => 'propertyId'));
69 77 }
70 78  
71 79 }
... ...
lib/api/ktcmis/classes/CMISPropertyCollection.inc.php
... ... @@ -55,29 +55,25 @@ abstract class CMISPropertyCollection {
55 55 static $LastModificationDate;
56 56 static $ChangeToken;
57 57 // TODO these definitions belong in their own classe definition (see property type definions,) but here will do for now
58   - static $propertyTypes;
  58 + static public $propertyTypes;
59 59  
60 60 function __construct()
61 61 {
62   - $this->propertyTypes = array('ObjectId' => 'propertyId',
63   - 'BaseType' => 'propertyString',
64   - 'ObjectTypeId' => 'propertyString',
65   - 'CreatedBy' => 'propertyString',
66   - 'CreationDate' => 'propertyDateTime',
67   - 'LastModifiedBy' => 'propertyString',
68   - 'LastModificationDate' => 'propertyDateTime',
69   - 'Name' => 'propertyString',
70   - 'ContentStreamAllowed' => 'propertyString',
71   - 'ContentStreamLength' => 'propertyInteger',
72   - 'ContentStreamMimeType' => 'propertyString',
73   - 'ContentStreamFilename' => 'propertyString',
74   - 'ContentStreamUri' => 'propertyUri',
75   - 'Uri' => 'propertyUri',
76   - 'AllowedChildObjectTypeIds' => 'propertyId',
77   - 'CreatedBy' => 'propertyString',
78   - 'CreationDate' => 'propertyDateTime',
79   - 'ChangeToken' => 'propertyString',
80   - 'ParentId' => 'propertyId');
  62 + self::$propertyTypes = array('ObjectId' => 'propertyId',
  63 + 'Author' => 'propertyString',
  64 + 'BaseType' => 'propertyString',
  65 + 'ObjectTypeId' => 'propertyString',
  66 + 'CreatedBy' => 'propertyString',
  67 + 'CreationDate' => 'propertyDateTime',
  68 + 'LastModifiedBy' => 'propertyString',
  69 + 'LastModificationDate' => 'propertyDateTime',
  70 + 'Name' => 'propertyString',
  71 + 'Uri' => 'propertyUri',
  72 + 'AllowedChildObjectTypeIds' => 'propertyId',
  73 + 'CreatedBy' => 'propertyString',
  74 + 'CreationDate' => 'propertyDateTime',
  75 + 'ChangeToken' => 'propertyString',
  76 + 'ParentId' => 'propertyId');
81 77 }
82 78  
83 79 /**
... ...
lib/api/ktcmis/ktcmis.inc.php
... ... @@ -458,12 +458,12 @@ class KTNavigationService extends KTCMISBase {
458 458 "message" => "Failed getting list of checked out documents"
459 459 );
460 460 }
461   -
  461 +
462 462 // convert to array format for external code
463 463 $co = array();
464   - foreach ($checkedout as $document)
  464 + foreach ($checkedout as $documentProperties)
465 465 {
466   - $co[] = $document->getProperty('ObjectId');
  466 + $co[] = CMISUtil::createObjectPropertiesEntry($documentProperties);;
467 467 }
468 468  
469 469 return array(
... ...
lib/api/ktcmis/services/CMISNavigationService.inc.php
... ... @@ -268,7 +268,7 @@ class CMISNavigationService {
268 268 foreach($results as $document)
269 269 {
270 270 $CMISDocument = new CMISDocumentObject($document->getId(), $this->ktapi);
271   - $checkedout[] = $CMISDocument;
  271 + $checkedout[] = $CMISDocument->getProperties();
272 272 }
273 273  
274 274 return $checkedout;
... ...
lib/api/ktcmis/util/CMISUtil.inc.php
... ... @@ -270,7 +270,20 @@ class CMISUtil {
270 270 static public function createObjectPropertiesEntry($properties)
271 271 {
272 272 $object = array();
  273 +
  274 + foreach(CMISPropertyCollection::$propertyTypes as $property => $type)
  275 + {
  276 + // hack for Author property
  277 + if ($property == 'Author') {
  278 + $object[$property] = array('value' => $properties->getValue($property));
  279 + }
  280 + else {
  281 + $object['properties'][$property] = array('type' => $type, 'value' => $properties->getValue($property));
  282 + }
  283 + }
273 284  
  285 + /* old static method */
  286 + /*
274 287 $object['Author'] = array('value' => $properties->getValue('Author'));
275 288  
276 289 $object['properties']['BaseType'] = array('type' => $properties->getFieldType('BaseType'),
... ... @@ -331,7 +344,10 @@ class CMISUtil {
331 344 'value' => $properties->getValue('ContentStreamUri'));
332 345 }
333 346 }
  347 + */
334 348  
  349 + /* what on earth was this for? */
  350 + /*
335 351 // if we have found a child/parent with one or more children/parents, recurse into the child/parent object
336 352 if (count($entry['items']) > 0) {
337 353 $object[$linkText] = CMISUtil::decodeObjectHierarchy($entry['items'], $linkText);
... ... @@ -341,6 +357,7 @@ class CMISUtil {
341 357 else {
342 358 $object[$linkText] = null;
343 359 }
  360 + */
344 361  
345 362 return $object;
346 363 }
... ...
webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php
... ... @@ -37,7 +37,11 @@ include_once CMIS_ATOM_LIB_FOLDER . 'VersioningService.inc.php';
37 37 include_once 'KT_cmis_atom_service_helper.inc.php';
38 38  
39 39 // TODO consider changing all responses from the webservice layer to return PEAR errors or success results instead of the half/half we have at the moment.
40   -// the half/half occurred because on initial services PEAR Error seemed unnecessary, but it has proven useful for some of the newer functions :)
  40 +// the half/half occurred because on initial services PEAR Error seemed unnecessary, but it has proven useful for some of the newer functions
  41 +
  42 +// TODO proper first/last links
  43 +// FIXME any incorrect or missing links
  44 +// FIXME ContentStreamAllowed tag is empty (at least sometimes)
41 45  
42 46 /**
43 47 * AtomPub Service: folder
... ... @@ -236,6 +240,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
236 240 $this->responseFeed = $feed;
237 241 return null;
238 242 }
  243 +
239 244 // list of failed objects?
240 245 if (is_array($response))
241 246 {
... ... @@ -277,16 +282,13 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service {
277 282 */
278 283 private function getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $feedType = 'children')
279 284 {
280   - if ($feedType == 'children')
281   - {
  285 + if ($feedType == 'children') {
282 286 $entries = $NavigationService->getChildren($repositoryId, $folderId, false, false);
283 287 }
284   - else if ($feedType == 'descendants')
285   - {
  288 + else if ($feedType == 'descendants') {
286 289 $entries = $NavigationService->getDescendants($repositoryId, $folderId, false, false);
287 290 }
288   - else
289   - {
  291 + else {
290 292 // error, we shouldn't be here, if we are then the wrong service/function was called
291 293 }
292 294  
... ... @@ -430,7 +432,6 @@ class KT_cmis_atom_service_type extends KT_cmis_atom_service {
430 432 /**
431 433 * AtomPub Service: checkedout
432 434 */
433   -// NOTE this is always an empty document, underlying API code still to be implemented
434 435 class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
435 436  
436 437 /**
... ... @@ -444,10 +445,11 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
444 445 $repositories = $RepositoryService->getRepositories();
445 446 $repositoryId = $repositories[0]['repositoryId'];
446 447  
447   - $checkedout = $NavigationService->getCheckedoutDocs($repositoryId);
  448 + $checkedout = $NavigationService->getCheckedOutDocs($repositoryId);
448 449  
449 450 //Create a new response feed
450 451 $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
  452 + $workspace = $feed->getWorkspace();
451 453  
452 454 $feed->newField('title', 'Checked out Documents', $feed);
453 455  
... ... @@ -460,27 +462,37 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
460 462  
461 463 // TODO get actual most recent update time, only use current if no other available
462 464 $feed->appendChild($feed->newElement('updated', KT_cmis_atom_service_helper::formatDatestamp()));
463   -
464   - foreach($checkedout as $document)
465   - {
466   - $entry = $feed->newEntry();
467   - $objectElement = $feed->newElement('cmis:object');
468   - $propertiesElement = $feed->newElement('cmis:properties');
469   -
470   - foreach($cmisEntry['properties'] as $propertyName => $property)
471   - {
472   - $propElement = $feed->newElement('cmis:' . $property['type']);
473   - $propElement->appendChild($feed->newAttr('cmis:name', $propertyName));
474   - $feed->newField('cmis:value', CMISUtil::boolToString($property['value']), $propElement);
475   - $propertiesElement->appendChild($propElement);
476   - }
  465 +
  466 + $link = $feed->newElement('link');
  467 + $link->appendChild($feed->newAttr('rel', 'self'));
  468 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/checkedout'));
  469 + $feed->appendChild($link);
  470 +
  471 + $link = $feed->newElement('link');
  472 + $link->appendChild($feed->newAttr('rel','first'));
  473 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/checkedout/pageNo=1&pageSize=0'));
  474 + $link->appendChild($feed->newAttr('type', 'application/atom+xml;type=feed'));
  475 + $feed->appendChild($link);
  476 +
  477 + $link = $feed->newElement('link');
  478 + $link->appendChild($feed->newAttr('rel','last'));
  479 + // TODO set page number correctly - to be done when we support paging the the API
  480 + $link->appendChild($feed->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/checkedout/pageNo=1&pageSize=0'));
  481 + $link->appendChild($feed->newAttr('type', 'application/atom+xml;type=feed'));
  482 + $feed->appendChild($link);
477 483  
478   - $objectElement->appendChild($propertiesElement);
479   - $entry->appendChild($objectElement);
  484 + foreach($checkedout as $cmisEntry)
  485 + {
  486 + KT_cmis_atom_service_helper::createObjectEntry($feed, $cmisEntry, $folderName);
  487 +
  488 +// // after each entry, add app:edited tag
  489 +// $feed->newField('app:edited', KT_cmis_atom_service_helper::formatDatestamp(), $feed);
480 490 }
481 491  
482   - $entry = null;
483   - $feed->newField('cmis:hasMoreItems', 'false', $entry, true);
  492 + $feed->newField('cmis:hasMoreItems', 'false', $feed);
  493 +
  494 +// $entry = null;
  495 +// $feed->newField('cmis:hasMoreItems', 'false', $entry, true);
484 496  
485 497 //Expose the responseFeed
486 498 $this->responseFeed = $feed;
... ... @@ -495,8 +507,8 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
495 507 $repositories = $RepositoryService->getRepositories();
496 508 $repositoryId = $repositories[0]['repositoryId'];
497 509  
498   - $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->parsedXMLContent['@children']['cmis:object']);
499   -
  510 + $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->parsedXMLContent['@children']);
  511 +
500 512 // check for existing object id as property of submitted object data
501 513 if (empty($cmisObjectProperties['ObjectId']))
502 514 {
... ... @@ -518,51 +530,9 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service {
518 530  
519 531 $this->setStatus(self::STATUS_CREATED);
520 532 $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $cmisObjectProperties['ObjectId'], 'POST');
521   -// $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $newObjectId, 'POST');
522 533  
523 534 //Expose the responseFeed
524 535 $this->responseFeed = $feed;
525   -
526   -// $checkedout = $NavigationService->getCheckedoutDocs($repositoryId);
527   -//
528   -// //Create a new response feed
529   -// $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI);
530   -//
531   -// $feed->newField('title', 'Checked out Documents', $feed);
532   -//
533   -// // TODO dynamic?
534   -// $feedElement = $feed->newField('author');
535   -// $element = $feed->newField('name', 'admin', $feedElement);
536   -// $feed->appendChild($feedElement);
537   -//
538   -// $feed->appendChild($feed->newElement('id', 'urn:uuid:checkedout'));
539   -//
540   -// // TODO get actual most recent update time, only use current if no other available
541   -// $feed->appendChild($feed->newElement('updated', KT_cmis_atom_service_helper::formatDatestamp()));
542   -//
543   -// foreach($checkedout as $document)
544   -// {
545   -// $entry = $feed->newEntry();
546   -// $objectElement = $feed->newElement('cmis:object');
547   -// $propertiesElement = $feed->newElement('cmis:properties');
548   -//
549   -// foreach($cmisEntry['properties'] as $propertyName => $property)
550   -// {
551   -// $propElement = $feed->newElement('cmis:' . $property['type']);
552   -// $propElement->appendChild($feed->newAttr('cmis:name', $propertyName));
553   -// $feed->newField('cmis:value', CMISUtil::boolToString($property['value']), $propElement);
554   -// $propertiesElement->appendChild($propElement);
555   -// }
556   -//
557   -// $objectElement->appendChild($propertiesElement);
558   -// $entry->appendChild($objectElement);
559   -// }
560   -//
561   -// $entry = null;
562   -// $feed->newField('cmis:hasMoreItems', 'false', $entry, true);
563   -//
564   -// //Expose the responseFeed
565   -// $this->responseFeed = $feed;
566 536 }
567 537  
568 538 }
... ... @@ -675,4 +645,64 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service {
675 645  
676 646 }
677 647  
  648 +class KT_cmis_atom_service_pwc extends KT_cmis_atom_service {
  649 +
  650 + /**
  651 + * Deals with GET actions for Private Working Copies.
  652 + * This includes individual Private Working Copy retrieval
  653 + */
  654 + public function GET_action()
  655 + {
  656 + $RepositoryService = new RepositoryService();
  657 + $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt());
  658 +
  659 + $repositories = $RepositoryService->getRepositories();
  660 + $repositoryId = $repositories[0]['repositoryId'];
  661 +
  662 + // determine whether we want the Private Working Copy entry feed or the actual physical Private Working Copy content.
  663 + // this depends on $this->params[1]
  664 + if (!empty($this->params[1]))
  665 + {
  666 + $this->getContentStream($ObjectService, $repositoryId);
  667 + return null;
  668 + }
  669 +
  670 + $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $this->params[0]);
  671 +
  672 + //Expose the responseFeed
  673 + $this->responseFeed = $feed;
  674 + }
  675 +
  676 + /**
  677 + * Deals with DELETE actions for Private Working Copies.
  678 + * This includes deletion of a specific version of a document (latest version) via deleteObject
  679 + * as well as deleteAllVersions
  680 + *
  681 + * @return 204 on success, 500 on error
  682 + */
  683 + public function DELETE_action()
  684 + {
  685 + // call the cancel checkout function
  686 + $RepositoryService = new RepositoryService();
  687 + $VersioningService = new VersioningService(KT_cmis_atom_service_helper::getKt());
  688 +
  689 + $repositories = $RepositoryService->getRepositories();
  690 + $repositoryId = $repositories[0]['repositoryId'];
  691 +
  692 + $response = $VersioningService->cancelCheckout($repositoryId, $this->params[0]);
  693 +
  694 + if (PEAR::isError($response))
  695 + {
  696 + $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage());
  697 + //Expose the responseFeed
  698 + $this->responseFeed = $feed;
  699 + return null;
  700 + }
  701 +
  702 + $this->setStatus(self::STATUS_NO_CONTENT);
  703 + $this->responseFeed = null;
  704 + }
  705 +
  706 +}
  707 +
678 708 ?>
679 709 \ No newline at end of file
... ...
webservice/atompub/cmis/KT_cmis_atom_service_helper.inc.php
... ... @@ -75,7 +75,7 @@ class KT_cmis_atom_service_helper {
75 75 {
76 76 $field = $response->newElement('content');
77 77 $field->appendChild($response->newAttr('type', $cmisEntry['properties']['ContentStreamMimeType']['value']));
78   - $field->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
  78 + $field->appendChild($response->newAttr('src', CMIS_APP_BASE_URI . $workspace . '/' . $type
79 79 . '/' . $cmisEntry['properties']['ObjectId']['value']
80 80 . '/' . $cmisEntry['properties']['ContentStreamFilename']['value']));
81 81 $entry->appendChild($field);
... ... @@ -190,14 +190,24 @@ class KT_cmis_atom_service_helper {
190 190 }
191 191  
192 192 // if the document is checked out and this is NOT the PWC, this link MUST be present
193   -// if (!empty($cmisEntry['properties']['ContentStreamLength']['value']))
194   -// {
195   -// $link = $response->newElement('link');
196   -// $link->appendChild($response->newAttr('rel', 'stream'));
197   -// $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type . '/' . $cmisEntry['properties']['ParentId']['value']));
198   -// $entry->appendChild($link);
199   -// }
200   -//
  193 + // NOTE at the moment the document and the PWC are the same object, so we always show it for a checked out document
  194 + // TODO separated code for PWC and actual document object
  195 + if (!empty($cmisEntry['properties']['VersionSeriesCheckedOutId']['value']))
  196 + {
  197 + $link = $response->newElement('link');
  198 + $link->appendChild($response->newAttr('rel', 'pwc'));
  199 + $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
  200 + . '/' . $cmisEntry['properties']['ObjectId']['value']
  201 + . '/' . $cmisEntry['properties']['ContentStreamFilename']['value']));
  202 + $entry->appendChild($link);
  203 + $link = $response->newElement('link');
  204 + $link->appendChild($response->newAttr('rel', 'source'));
  205 + $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
  206 + . '/' . $cmisEntry['properties']['ObjectId']['value']
  207 + . '/' . $cmisEntry['properties']['ContentStreamFilename']['value']));
  208 + $entry->appendChild($link);
  209 + }
  210 +
201 211 // $link = $response->newElement('link');
202 212 // $link->appendChild($response->newAttr('rel', 'stream'));
203 213 // $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type
... ... @@ -253,9 +263,10 @@ class KT_cmis_atom_service_helper {
253 263 // after every entry, append a cmis:terminator tag
254 264 $entry->appendChild($response->newElement('cmis:terminator'));
255 265  
256   - if ($method == 'POST') {
  266 + // TODO check determination of when to add app:edited tag
  267 +// if ($method == 'POST') {
257 268 $entry->appendChild($response->newElement('app:edited', self::formatDatestamp()));
258   - }
  269 +// }
259 270 }
260 271  
261 272 /**
... ... @@ -415,9 +426,17 @@ class KT_cmis_atom_service_helper {
415 426 {
416 427 $properties = array();
417 428  
418   - foreach($xmlArray as $xmlElement)
  429 + // find cmis:object tag
  430 + $baseCmisObject = KT_cmis_atom_service_helper::findTag('cmis:object', $xmlArray, null, false);
  431 + if(count($baseCmisObject) <= 0)
419 432 {
420   - foreach($xmlElement['@children'] as $key => $childElement)
  433 + $entryObject = KT_cmis_atom_service_helper::findTag('entry', $xmlArray, null, false);
  434 + $baseCmisObject = KT_cmis_atom_service_helper::findTag('cmis:object', $entryObject['@children'], null, true);
  435 + }
  436 +
  437 + if(count($baseCmisObject)>0)
  438 + {
  439 + foreach($baseCmisObject['@children'] as $key => $childElement)
421 440 {
422 441 if ($key == 'cmis:properties')
423 442 {
... ... @@ -466,6 +485,34 @@ class KT_cmis_atom_service_helper {
466 485 if (is_null($time)) $time = time();
467 486 return date('Y-m-d H:i:s', $time);
468 487 }
  488 +
  489 + //TODO: Add key information to be able to find the same tag in the original struct (MarkH)
  490 + static public function findTag($tagName=NULL,$xml=array(),$tagArray=NULL,$deep=false){
  491 + $tagArray=is_array($tagArray)?$tagArray:array();
  492 + foreach($xml as $xmlTag=>$content){
  493 + if($xmlTag===$tagName){
  494 + $tagArray[]=$content;
  495 + }
  496 + if($deep){
  497 + foreach($content as $contentTags){
  498 + if(is_array($contentTags['@children'])) {
  499 + if(count($contentTags['@children'])>0) $tagArray=self::findTag($tagName,$contentTags['@children'],$tagArray);
  500 + }
  501 + }
  502 + }
  503 + }
  504 + //TODO: this is very ugly. Change it. (MarkH)
  505 + return self::rebaseArray($tagArray);
  506 + }
  507 +
  508 + static public function rebaseArray($arr=array()){
  509 + //Force Array
  510 + $arr=is_array($arr)?$arr:array();
  511 +
  512 + //Rebase recursively
  513 + if(count($arr)===1)$arr=self::rebaseArray($arr[0]);
  514 + return $arr;
  515 + }
469 516  
470 517 }
471 518  
... ...
webservice/atompub/cmis/index.php
... ... @@ -113,6 +113,7 @@ if ($workspace != &#39;servicedocument&#39;)
113 113 {
114 114 $APP->registerService('dms', 'type', 'KT_cmis_atom_service_type', 'Object Type Entry', null, 'type');
115 115 $APP->registerService('dms', 'document', 'KT_cmis_atom_service_document', 'Document Entry', null, 'document');
  116 + $APP->registerService('dms', 'pwc', 'KT_cmis_atom_service_pwc', 'Private Working Copy', null, 'pwc');
116 117 }
117 118  
118 119 //Execute the current url/header request
... ...
webservice/classes/atompub/cmis/NavigationService.inc.php
... ... @@ -109,9 +109,9 @@ class NavigationService extends KTNavigationService {
109 109 * @param int $skipCount
110 110 * @return array $checkedout The collection of checked out documents
111 111 */
112   - function getCheckedoutDocs($repositoryId, $folderId = null, $filter = '', $maxItems = 0, $skipCount = 0)
  112 + function getCheckedOutDocs($repositoryId, $folderId = null, $filter = '', $maxItems = 0, $skipCount = 0)
113 113 {
114   - $checkedout = parent::getObjectParents($repositoryId, $folderId, $filter, $maxItems, $skipCount);
  114 + $result = parent::getCheckedOutDocs($repositoryId, $folderId, $filter, $maxItems, $skipCount);
115 115  
116 116 if ($result['status_code'] == 0)
117 117 {
... ...
webservice/classes/atompub/cmis/VersioningService.inc.php
... ... @@ -48,6 +48,30 @@ class VersioningService extends KTVersioningService {
48 48 return new PEAR_Error($result['message']);
49 49 }
50 50 }
  51 +
  52 + /**
  53 + * Reverses the effect of a checkout: I.E. deletes the PWC (Private Working Copy) and re-sets the status of the document to "not checked out"
  54 + *
  55 + * @param string $repositoryId
  56 + * @param string $documentId
  57 + * @param string $changeToken [optional]
  58 + */
  59 + // TODO exceptions:
  60 + // • ConstraintViolationException: The Repository SHALL throw this exception if ANY of the following conditions are met:
  61 + // o The Document’s Object-Type definition’s versionable attribute is FALSE.
  62 + // • updateConflictException
  63 + // • versioningException
  64 + public function cancelCheckOut($repositoryId, $documentId, $changeToken = '')
  65 + {
  66 + $result = parent::cancelCheckOut($repositoryId, $documentId, $changeToken);
  67 +
  68 + if ($result['status_code'] == 0) {
  69 + return $result['results'];
  70 + }
  71 + else {
  72 + return new PEAR_Error($result['message']);
  73 + }
  74 + }
51 75  
52 76 }
53 77  
... ...