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 | 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 != 'servicedocument') |
| 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 | ... | ... |