Commit 1f10b1709cd50df4a45d89facbe0c4e53a2b3653
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
Showing
11 changed files
with
235 additions
and
110 deletions
ktapi/ktapi.inc.php
| @@ -3254,6 +3254,8 @@ class KTAPI | @@ -3254,6 +3254,8 @@ class KTAPI | ||
| 3254 | * @param boolean $userSpecific limit to current user | 3254 | * @param boolean $userSpecific limit to current user |
| 3255 | * @return $checkedout An array of checked out documents | 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 | public function get_checkedout_docs($userSpecific = true) | 3259 | public function get_checkedout_docs($userSpecific = true) |
| 3258 | { | 3260 | { |
| 3259 | $checkedout = array(); | 3261 | $checkedout = array(); |
lib/api/ktcmis/classes/CMISDocumentPropertyCollection.inc.php
| @@ -66,6 +66,14 @@ class CMISDocumentPropertyCollection extends CMISPropertyCollection { | @@ -66,6 +66,14 @@ class CMISDocumentPropertyCollection extends CMISPropertyCollection { | ||
| 66 | function __construct() | 66 | function __construct() |
| 67 | { | 67 | { |
| 68 | parent::__construct(); | 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,29 +55,25 @@ abstract class CMISPropertyCollection { | ||
| 55 | static $LastModificationDate; | 55 | static $LastModificationDate; |
| 56 | static $ChangeToken; | 56 | static $ChangeToken; |
| 57 | // TODO these definitions belong in their own classe definition (see property type definions,) but here will do for now | 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 | function __construct() | 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,12 +458,12 @@ class KTNavigationService extends KTCMISBase { | ||
| 458 | "message" => "Failed getting list of checked out documents" | 458 | "message" => "Failed getting list of checked out documents" |
| 459 | ); | 459 | ); |
| 460 | } | 460 | } |
| 461 | - | 461 | + |
| 462 | // convert to array format for external code | 462 | // convert to array format for external code |
| 463 | $co = array(); | 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 | return array( | 469 | return array( |
lib/api/ktcmis/services/CMISNavigationService.inc.php
| @@ -268,7 +268,7 @@ class CMISNavigationService { | @@ -268,7 +268,7 @@ class CMISNavigationService { | ||
| 268 | foreach($results as $document) | 268 | foreach($results as $document) |
| 269 | { | 269 | { |
| 270 | $CMISDocument = new CMISDocumentObject($document->getId(), $this->ktapi); | 270 | $CMISDocument = new CMISDocumentObject($document->getId(), $this->ktapi); |
| 271 | - $checkedout[] = $CMISDocument; | 271 | + $checkedout[] = $CMISDocument->getProperties(); |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | return $checkedout; | 274 | return $checkedout; |
lib/api/ktcmis/util/CMISUtil.inc.php
| @@ -270,7 +270,20 @@ class CMISUtil { | @@ -270,7 +270,20 @@ class CMISUtil { | ||
| 270 | static public function createObjectPropertiesEntry($properties) | 270 | static public function createObjectPropertiesEntry($properties) |
| 271 | { | 271 | { |
| 272 | $object = array(); | 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 | $object['Author'] = array('value' => $properties->getValue('Author')); | 287 | $object['Author'] = array('value' => $properties->getValue('Author')); |
| 275 | 288 | ||
| 276 | $object['properties']['BaseType'] = array('type' => $properties->getFieldType('BaseType'), | 289 | $object['properties']['BaseType'] = array('type' => $properties->getFieldType('BaseType'), |
| @@ -331,7 +344,10 @@ class CMISUtil { | @@ -331,7 +344,10 @@ class CMISUtil { | ||
| 331 | 'value' => $properties->getValue('ContentStreamUri')); | 344 | 'value' => $properties->getValue('ContentStreamUri')); |
| 332 | } | 345 | } |
| 333 | } | 346 | } |
| 347 | + */ | ||
| 334 | 348 | ||
| 349 | + /* what on earth was this for? */ | ||
| 350 | + /* | ||
| 335 | // if we have found a child/parent with one or more children/parents, recurse into the child/parent object | 351 | // if we have found a child/parent with one or more children/parents, recurse into the child/parent object |
| 336 | if (count($entry['items']) > 0) { | 352 | if (count($entry['items']) > 0) { |
| 337 | $object[$linkText] = CMISUtil::decodeObjectHierarchy($entry['items'], $linkText); | 353 | $object[$linkText] = CMISUtil::decodeObjectHierarchy($entry['items'], $linkText); |
| @@ -341,6 +357,7 @@ class CMISUtil { | @@ -341,6 +357,7 @@ class CMISUtil { | ||
| 341 | else { | 357 | else { |
| 342 | $object[$linkText] = null; | 358 | $object[$linkText] = null; |
| 343 | } | 359 | } |
| 360 | + */ | ||
| 344 | 361 | ||
| 345 | return $object; | 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,7 +37,11 @@ include_once CMIS_ATOM_LIB_FOLDER . 'VersioningService.inc.php'; | ||
| 37 | include_once 'KT_cmis_atom_service_helper.inc.php'; | 37 | include_once 'KT_cmis_atom_service_helper.inc.php'; |
| 38 | 38 | ||
| 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. | 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 | * AtomPub Service: folder | 47 | * AtomPub Service: folder |
| @@ -236,6 +240,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { | @@ -236,6 +240,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { | ||
| 236 | $this->responseFeed = $feed; | 240 | $this->responseFeed = $feed; |
| 237 | return null; | 241 | return null; |
| 238 | } | 242 | } |
| 243 | + | ||
| 239 | // list of failed objects? | 244 | // list of failed objects? |
| 240 | if (is_array($response)) | 245 | if (is_array($response)) |
| 241 | { | 246 | { |
| @@ -277,16 +282,13 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { | @@ -277,16 +282,13 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { | ||
| 277 | */ | 282 | */ |
| 278 | private function getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $feedType = 'children') | 283 | private function getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $folderName, $feedType = 'children') |
| 279 | { | 284 | { |
| 280 | - if ($feedType == 'children') | ||
| 281 | - { | 285 | + if ($feedType == 'children') { |
| 282 | $entries = $NavigationService->getChildren($repositoryId, $folderId, false, false); | 286 | $entries = $NavigationService->getChildren($repositoryId, $folderId, false, false); |
| 283 | } | 287 | } |
| 284 | - else if ($feedType == 'descendants') | ||
| 285 | - { | 288 | + else if ($feedType == 'descendants') { |
| 286 | $entries = $NavigationService->getDescendants($repositoryId, $folderId, false, false); | 289 | $entries = $NavigationService->getDescendants($repositoryId, $folderId, false, false); |
| 287 | } | 290 | } |
| 288 | - else | ||
| 289 | - { | 291 | + else { |
| 290 | // error, we shouldn't be here, if we are then the wrong service/function was called | 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,7 +432,6 @@ class KT_cmis_atom_service_type extends KT_cmis_atom_service { | ||
| 430 | /** | 432 | /** |
| 431 | * AtomPub Service: checkedout | 433 | * AtomPub Service: checkedout |
| 432 | */ | 434 | */ |
| 433 | -// NOTE this is always an empty document, underlying API code still to be implemented | ||
| 434 | class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | 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,10 +445,11 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | ||
| 444 | $repositories = $RepositoryService->getRepositories(); | 445 | $repositories = $RepositoryService->getRepositories(); |
| 445 | $repositoryId = $repositories[0]['repositoryId']; | 446 | $repositoryId = $repositories[0]['repositoryId']; |
| 446 | 447 | ||
| 447 | - $checkedout = $NavigationService->getCheckedoutDocs($repositoryId); | 448 | + $checkedout = $NavigationService->getCheckedOutDocs($repositoryId); |
| 448 | 449 | ||
| 449 | //Create a new response feed | 450 | //Create a new response feed |
| 450 | $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI); | 451 | $feed = new KT_cmis_atom_responseFeed_GET(CMIS_APP_BASE_URI); |
| 452 | + $workspace = $feed->getWorkspace(); | ||
| 451 | 453 | ||
| 452 | $feed->newField('title', 'Checked out Documents', $feed); | 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,27 +462,37 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | ||
| 460 | 462 | ||
| 461 | // TODO get actual most recent update time, only use current if no other available | 463 | // TODO get actual most recent update time, only use current if no other available |
| 462 | $feed->appendChild($feed->newElement('updated', KT_cmis_atom_service_helper::formatDatestamp())); | 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 | //Expose the responseFeed | 497 | //Expose the responseFeed |
| 486 | $this->responseFeed = $feed; | 498 | $this->responseFeed = $feed; |
| @@ -495,8 +507,8 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | @@ -495,8 +507,8 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | ||
| 495 | $repositories = $RepositoryService->getRepositories(); | 507 | $repositories = $RepositoryService->getRepositories(); |
| 496 | $repositoryId = $repositories[0]['repositoryId']; | 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 | // check for existing object id as property of submitted object data | 512 | // check for existing object id as property of submitted object data |
| 501 | if (empty($cmisObjectProperties['ObjectId'])) | 513 | if (empty($cmisObjectProperties['ObjectId'])) |
| 502 | { | 514 | { |
| @@ -518,51 +530,9 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | @@ -518,51 +530,9 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | ||
| 518 | 530 | ||
| 519 | $this->setStatus(self::STATUS_CREATED); | 531 | $this->setStatus(self::STATUS_CREATED); |
| 520 | $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'); |
| 521 | -// $feed = KT_cmis_atom_service_helper::getObjectFeed($this, $ObjectService, $repositoryId, $newObjectId, 'POST'); | ||
| 522 | 533 | ||
| 523 | //Expose the responseFeed | 534 | //Expose the responseFeed |
| 524 | $this->responseFeed = $feed; | 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,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 | \ No newline at end of file | 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,7 +75,7 @@ class KT_cmis_atom_service_helper { | ||
| 75 | { | 75 | { |
| 76 | $field = $response->newElement('content'); | 76 | $field = $response->newElement('content'); |
| 77 | $field->appendChild($response->newAttr('type', $cmisEntry['properties']['ContentStreamMimeType']['value'])); | 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 | . '/' . $cmisEntry['properties']['ObjectId']['value'] | 79 | . '/' . $cmisEntry['properties']['ObjectId']['value'] |
| 80 | . '/' . $cmisEntry['properties']['ContentStreamFilename']['value'])); | 80 | . '/' . $cmisEntry['properties']['ContentStreamFilename']['value'])); |
| 81 | $entry->appendChild($field); | 81 | $entry->appendChild($field); |
| @@ -190,14 +190,24 @@ class KT_cmis_atom_service_helper { | @@ -190,14 +190,24 @@ class KT_cmis_atom_service_helper { | ||
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | // if the document is checked out and this is NOT the PWC, this link MUST be present | 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 | // $link = $response->newElement('link'); | 211 | // $link = $response->newElement('link'); |
| 202 | // $link->appendChild($response->newAttr('rel', 'stream')); | 212 | // $link->appendChild($response->newAttr('rel', 'stream')); |
| 203 | // $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type | 213 | // $link->appendChild($response->newAttr('href', CMIS_APP_BASE_URI . $workspace . '/' . $type |
| @@ -253,9 +263,10 @@ class KT_cmis_atom_service_helper { | @@ -253,9 +263,10 @@ class KT_cmis_atom_service_helper { | ||
| 253 | // after every entry, append a cmis:terminator tag | 263 | // after every entry, append a cmis:terminator tag |
| 254 | $entry->appendChild($response->newElement('cmis:terminator')); | 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 | $entry->appendChild($response->newElement('app:edited', self::formatDatestamp())); | 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,9 +426,17 @@ class KT_cmis_atom_service_helper { | ||
| 415 | { | 426 | { |
| 416 | $properties = array(); | 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 | if ($key == 'cmis:properties') | 441 | if ($key == 'cmis:properties') |
| 423 | { | 442 | { |
| @@ -466,6 +485,34 @@ class KT_cmis_atom_service_helper { | @@ -466,6 +485,34 @@ class KT_cmis_atom_service_helper { | ||
| 466 | if (is_null($time)) $time = time(); | 485 | if (is_null($time)) $time = time(); |
| 467 | return date('Y-m-d H:i:s', $time); | 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 != 'servicedocument') | @@ -113,6 +113,7 @@ if ($workspace != 'servicedocument') | ||
| 113 | { | 113 | { |
| 114 | $APP->registerService('dms', 'type', 'KT_cmis_atom_service_type', 'Object Type Entry', null, 'type'); | 114 | $APP->registerService('dms', 'type', 'KT_cmis_atom_service_type', 'Object Type Entry', null, 'type'); |
| 115 | $APP->registerService('dms', 'document', 'KT_cmis_atom_service_document', 'Document Entry', null, 'document'); | 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 | //Execute the current url/header request | 119 | //Execute the current url/header request |
webservice/classes/atompub/cmis/NavigationService.inc.php
| @@ -109,9 +109,9 @@ class NavigationService extends KTNavigationService { | @@ -109,9 +109,9 @@ class NavigationService extends KTNavigationService { | ||
| 109 | * @param int $skipCount | 109 | * @param int $skipCount |
| 110 | * @return array $checkedout The collection of checked out documents | 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 | if ($result['status_code'] == 0) | 116 | if ($result['status_code'] == 0) |
| 117 | { | 117 | { |
webservice/classes/atompub/cmis/VersioningService.inc.php
| @@ -48,6 +48,30 @@ class VersioningService extends KTVersioningService { | @@ -48,6 +48,30 @@ class VersioningService extends KTVersioningService { | ||
| 48 | return new PEAR_Error($result['message']); | 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 |