Commit 2aaa0bf9f4a69feef0686e1b6cf526c6054965af
1 parent
73636462
Update CMIS Checkout, Cancel Checkout, Checkin, and begin removing unnecessary t…
…op layer in webservice Story ID:2295472. Update KT CMIS implementation to 1.0 compliance Committed by: Paul Barrett
Showing
8 changed files
with
129 additions
and
179 deletions
lib/api/ktcmis/ktObjectService.inc.php
| @@ -181,12 +181,13 @@ class KTObjectService extends KTCMISBase { | @@ -181,12 +181,13 @@ class KTObjectService extends KTCMISBase { | ||
| 181 | * | 181 | * |
| 182 | * @param string $repositoryId | 182 | * @param string $repositoryId |
| 183 | * @param string $objectId | 183 | * @param string $objectId |
| 184 | + * @param string $streamId [optional for documents] Specifies the rendition to retrieve if not original document | ||
| 184 | * @return string $contentStream (binary or text data) | 185 | * @return string $contentStream (binary or text data) |
| 185 | */ | 186 | */ |
| 186 | - function getContentStream($repositoryId, $objectId) | 187 | + function getContentStream($repositoryId, $objectId, $streamId = null) |
| 187 | { | 188 | { |
| 188 | try { | 189 | try { |
| 189 | - $contentStream = $this->ObjectService->getContentStream($repositoryId, $objectId); | 190 | + $contentStream = $this->ObjectService->getContentStream($repositoryId, $objectId, $streamId); |
| 190 | } | 191 | } |
| 191 | catch (Exception $e) | 192 | catch (Exception $e) |
| 192 | { | 193 | { |
lib/api/ktcmis/ktVersioningService.inc.php
| @@ -110,15 +110,14 @@ class KTVersioningService extends KTCMISBase { | @@ -110,15 +110,14 @@ class KTVersioningService extends KTCMISBase { | ||
| 110 | * Checks out a document and creates the PWC (Private Working Copy) which will represent the checked out document | 110 | * Checks out a document and creates the PWC (Private Working Copy) which will represent the checked out document |
| 111 | * | 111 | * |
| 112 | * @param string $repositoryId | 112 | * @param string $repositoryId |
| 113 | - * @param string $documentId | ||
| 114 | - * @param string $changeToken [optional] | 113 | + * @param string $objectId |
| 115 | * @return array results | 114 | * @return array results |
| 116 | */ | 115 | */ |
| 117 | // TODO set up delivery of content stream? or is that up to the CMIS client? | 116 | // TODO set up delivery of content stream? or is that up to the CMIS client? |
| 118 | - public function checkOut($repositoryId, $documentId, $changeToken = '') | 117 | + public function checkOut($repositoryId, $objectId) |
| 119 | { | 118 | { |
| 120 | try { | 119 | try { |
| 121 | - $result = $this->VersioningService->checkOut($repositoryId, $documentId, $changeToken); | 120 | + $result = $this->VersioningService->checkOut($repositoryId, $objectId); |
| 122 | } | 121 | } |
| 123 | catch (Exception $e) | 122 | catch (Exception $e) |
| 124 | { | 123 | { |
| @@ -138,18 +137,17 @@ class KTVersioningService extends KTCMISBase { | @@ -138,18 +137,17 @@ class KTVersioningService extends KTCMISBase { | ||
| 138 | * 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" | 137 | * 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" |
| 139 | * | 138 | * |
| 140 | * @param string $repositoryId | 139 | * @param string $repositoryId |
| 141 | - * @param string $documentId | ||
| 142 | - * @param string $changeToken [optional] | 140 | + * @param string $objectId |
| 143 | */ | 141 | */ |
| 144 | // TODO exceptions: | 142 | // TODO exceptions: |
| 145 | // • ConstraintViolationException: The Repository SHALL throw this exception if ANY of the following conditions are met: | 143 | // • ConstraintViolationException: The Repository SHALL throw this exception if ANY of the following conditions are met: |
| 146 | // o The Document’s Object-Type definition’s versionable attribute is FALSE. | 144 | // o The Document’s Object-Type definition’s versionable attribute is FALSE. |
| 147 | // • updateConflictException | 145 | // • updateConflictException |
| 148 | // • versioningException | 146 | // • versioningException |
| 149 | - public function cancelCheckOut($repositoryId, $documentId, $changeToken = '') | 147 | + public function cancelCheckOut($repositoryId, $objectId) |
| 150 | { | 148 | { |
| 151 | try { | 149 | try { |
| 152 | - $result = $this->VersioningService->cancelCheckOut($repositoryId, $documentId, $changeToken); | 150 | + $result = $this->VersioningService->cancelCheckOut($repositoryId, $objectId); |
| 153 | } | 151 | } |
| 154 | catch (Exception $e) | 152 | catch (Exception $e) |
| 155 | { | 153 | { |
| @@ -169,18 +167,22 @@ class KTVersioningService extends KTCMISBase { | @@ -169,18 +167,22 @@ class KTVersioningService extends KTCMISBase { | ||
| 169 | * Checks in a checked out document | 167 | * Checks in a checked out document |
| 170 | * | 168 | * |
| 171 | * @param string $repositoryId | 169 | * @param string $repositoryId |
| 172 | - * @param string $documentId | ||
| 173 | - * @param boolean $major | ||
| 174 | - * @param string $changeToken [optional] | 170 | + * @param string $objectId |
| 171 | + * @param boolean $major [optional] defaults to true | ||
| 175 | * @param array $properties [optional] | 172 | * @param array $properties [optional] |
| 176 | * @param contentStream $contentStream [optional] | 173 | * @param contentStream $contentStream [optional] |
| 177 | * @param string $checkinComment [optional] | 174 | * @param string $checkinComment [optional] |
| 178 | - * @return string $documentId | 175 | + * @param array $policies |
| 176 | + * @param array $addACEs | ||
| 177 | + * @param array $removeACEs | ||
| 178 | + * @return string $objectId | ||
| 179 | */ | 179 | */ |
| 180 | - public function checkIn($repositoryId, $documentId, $major, $contentStream = null, $changeToken = '', $properties = array(), $checkinComment = '') | 180 | + public function checkIn($repositoryId, $objectId, $major = true, $properties = array(), $contentStream = null, |
| 181 | + $checkinComment = '', $policies = array(), $addACEs = array(), $removeACEs = array()) | ||
| 181 | { | 182 | { |
| 182 | try { | 183 | try { |
| 183 | - $result = $this->VersioningService->checkIn($repositoryId, $documentId, $major, $contentStream, $changeToken, $properties, $checkinComment); | 184 | + $result = $this->VersioningService->checkIn($repositoryId, $objectId, $major, $properties, $contentStream, |
| 185 | + $checkinComment, $policies, $addACEs, $removeACEs); | ||
| 184 | } | 186 | } |
| 185 | catch (Exception $e) | 187 | catch (Exception $e) |
| 186 | { | 188 | { |
lib/api/ktcmis/services/CMISObjectService.inc.php
| @@ -401,16 +401,16 @@ class CMISObjectService { | @@ -401,16 +401,16 @@ class CMISObjectService { | ||
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | /** | 403 | /** |
| 404 | - * Fetches the content stream data for an object | 404 | + * Fetches the content stream data for an object, or fetched a rendition stream for a specified rendition |
| 405 | * | 405 | * |
| 406 | * @param string $repositoryId | 406 | * @param string $repositoryId |
| 407 | * @param string $objectId | 407 | * @param string $objectId |
| 408 | - * @return string $contentStream (binary or text data) | 408 | + * @param string $streamId [optional for documents] Specifies the rendition to retrieve if not original document |
| 409 | + * @return string $contentStream (binary [base64 encoded] or text data) | ||
| 409 | */ | 410 | */ |
| 410 | - // NOTE streamNotSupportedException: The Repository SHALL throw this exception if the Object-Type definition | ||
| 411 | - // specified by the objectId parameter’s “contentStreamAllowed� attribute is set to “not allowed�. | ||
| 412 | - // | ||
| 413 | - function getContentStream($repositoryId, $objectId) | 411 | + // NOTE Each CMIS protocol binding MAY provide a way for fetching a sub-range within a content stream, |
| 412 | + // in a manner appropriate to that protocol. | ||
| 413 | + function getContentStream($repositoryId, $objectId, $streamId = null) | ||
| 414 | { | 414 | { |
| 415 | $contentStream = null; | 415 | $contentStream = null; |
| 416 | 416 | ||
| @@ -426,13 +426,11 @@ class CMISObjectService { | @@ -426,13 +426,11 @@ class CMISObjectService { | ||
| 426 | $objectClass = 'CMIS' . $typeId . 'Object'; | 426 | $objectClass = 'CMIS' . $typeId . 'Object'; |
| 427 | $CMISObject = new $objectClass($objectId, $this->ktapi); | 427 | $CMISObject = new $objectClass($objectId, $this->ktapi); |
| 428 | 428 | ||
| 429 | - // if content stream is not allowed for this object type definition, throw a ConstraintViolationException | 429 | + // if content stream is not allowed for this object type definition, or the specified object does not have |
| 430 | + // a content/rendition stream, throw a ConstraintViolationException | ||
| 430 | if (($CMISObject->getAttribute('contentStreamAllowed') == 'notAllowed')) | 431 | if (($CMISObject->getAttribute('contentStreamAllowed') == 'notAllowed')) |
| 431 | { | 432 | { |
| 432 | - // NOTE spec version 0.61c specifies both a ConstraintViolationException and a StreamNotSupportedException | ||
| 433 | - // for this case. Choosing to throw StreamNotSupportedException until the specification is clarified | ||
| 434 | - // as it is a more specific exception | ||
| 435 | - throw new StreamNotSupportedException('Content Streams are not allowed for this object type'); | 433 | + throw new ConstraintViolationException('This object does not have a content stream of the requested type'); |
| 436 | } | 434 | } |
| 437 | 435 | ||
| 438 | // now go on to fetching the content stream | 436 | // now go on to fetching the content stream |
lib/api/ktcmis/services/CMISVersioningService.inc.php
| @@ -71,54 +71,58 @@ class CMISVersioningService { | @@ -71,54 +71,58 @@ class CMISVersioningService { | ||
| 71 | * Checks out a document and creates the PWC (Private Working Copy) which will represent the checked out document | 71 | * Checks out a document and creates the PWC (Private Working Copy) which will represent the checked out document |
| 72 | * | 72 | * |
| 73 | * @param string $repositoryId | 73 | * @param string $repositoryId |
| 74 | - * @param string $documentId | ||
| 75 | - * @param string $changeToken [optional] | ||
| 76 | - * @return string $documentId The id of the PWC object | 74 | + * @param string $objectId |
| 75 | + * @return string $objectId The id of the PWC object | ||
| 77 | * @return boolean $contentCopied TRUE if contentStream is a copy of the document content stream, FALSE if contentStream not set | 76 | * @return boolean $contentCopied TRUE if contentStream is a copy of the document content stream, FALSE if contentStream not set |
| 78 | */ | 77 | */ |
| 79 | - // TODO exceptions: | ||
| 80 | - // • versioningException: The repository MAY throw this exception if the object is a non-current Document Version. | ||
| 81 | // NOTE since we need to return two values, we return one via argument by reference | 78 | // NOTE since we need to return two values, we return one via argument by reference |
| 82 | - // since $documentId already exists in the argument list, that was chosen as the "return by reference" value | 79 | + // since $objectId already exists in the argument list, that was chosen as the "return by reference" value |
| 83 | // TODO set up delivery of content stream? or is that up to the CMIS client? | 80 | // TODO set up delivery of content stream? or is that up to the CMIS client? |
| 84 | - public function checkOut($repositoryId, &$documentId, $changeToken = '') | 81 | + public function checkOut($repositoryId, &$objectId) |
| 85 | { | 82 | { |
| 86 | $contentCopied = false; | 83 | $contentCopied = false; |
| 87 | - | ||
| 88 | - $documentId = CMISUtil::decodeObjectId($documentId, $typeId); | 84 | + |
| 85 | + $objectId = CMISUtil::decodeObjectId($objectId, $typeId); | ||
| 89 | 86 | ||
| 90 | // NOTE We are not planning on persisting the PWC beyond the current session, it will be re-created on access of the checked out document | 87 | // NOTE We are not planning on persisting the PWC beyond the current session, it will be re-created on access of the checked out document |
| 91 | // TODO consider persisting in the database? How will this relate to JSR if we are switching to that? | 88 | // TODO consider persisting in the database? How will this relate to JSR if we are switching to that? |
| 92 | // NOTE within the current system it is assumed if a new document metadata version is created that this is the latest version of the document | 89 | // NOTE within the current system it is assumed if a new document metadata version is created that this is the latest version of the document |
| 93 | // TODO see if there is an easy way to modify this, else we may not have an easy way to persist PWC objects | 90 | // TODO see if there is an easy way to modify this, else we may not have an easy way to persist PWC objects |
| 94 | - | 91 | + |
| 95 | // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). | 92 | // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). |
| 96 | try { | 93 | try { |
| 97 | - $pwc = new CMISDocumentObject($documentId, $this->ktapi); | 94 | + $pwc = new CMISDocumentObject($objectId, $this->ktapi); |
| 98 | } | 95 | } |
| 99 | catch (exception $e) { | 96 | catch (exception $e) { |
| 100 | throw new UpdateConflictException($e->getMessage()); | 97 | throw new UpdateConflictException($e->getMessage()); |
| 101 | } | 98 | } |
| 102 | - | 99 | + |
| 103 | // throw exception if the object is not versionable | 100 | // throw exception if the object is not versionable |
| 104 | if (!$pwc->getAttribute('versionable')) { | 101 | if (!$pwc->getAttribute('versionable')) { |
| 105 | throw new ConstraintViolationException('This document is not versionable and may not be checked out'); | 102 | throw new ConstraintViolationException('This document is not versionable and may not be checked out'); |
| 106 | } | 103 | } |
| 107 | - | 104 | + |
| 105 | + // check that this is the latest version | ||
| 106 | + if ($pwc->getProperty('isLatestVersion') != true) { | ||
| 107 | + throw new VersioningException('The document is not the latest version and cannot be checked out'); | ||
| 108 | + } | ||
| 109 | + | ||
| 108 | // NOTE KTAPI as currently implemented does not give a direct response which indicates if the document is already checked out, | 110 | // NOTE KTAPI as currently implemented does not give a direct response which indicates if the document is already checked out, |
| 109 | // as long as the same user is calling the checkout again, so should we add a check here specifically? | 111 | // as long as the same user is calling the checkout again, so should we add a check here specifically? |
| 110 | 112 | ||
| 111 | // run checkout process - set $download = false (third function argument) as we want to return the document content via the contentStream | 113 | // run checkout process - set $download = false (third function argument) as we want to return the document content via the contentStream |
| 112 | - $response = $this->ktapi->checkout_document($documentId, 'CMIS Checkout Action', false, $sig_username, $sig_password); | 114 | + $response = $this->ktapi->checkout_document($objectId, 'CMIS Checkout Action', false, $sig_username, $sig_password); |
| 113 | // if there was an error, throw an exception | 115 | // if there was an error, throw an exception |
| 114 | if ($response['status_code'] == 1) { | 116 | if ($response['status_code'] == 1) { |
| 115 | throw new StorageException($response['message']); | 117 | throw new StorageException($response['message']); |
| 116 | - }; | ||
| 117 | - | 118 | + } |
| 119 | + | ||
| 118 | // if successful, set $contentCopied = true; unless contentStream is not set | 120 | // if successful, set $contentCopied = true; unless contentStream is not set |
| 119 | - if ($pwc->getProperty('contentStreamFilename') != '') $contentCopied = true; | ||
| 120 | - $documentId = CMISUtil::encodeObjectId(DOCUMENT, $documentId); | ||
| 121 | - | 121 | + if ($pwc->getProperty('contentStreamFilename') != '') { |
| 122 | + $contentCopied = true; | ||
| 123 | + } | ||
| 124 | + $objectId = CMISUtil::encodeObjectId(DOCUMENT, $objectId); | ||
| 125 | + | ||
| 122 | // mark document object as checked out | 126 | // mark document object as checked out |
| 123 | $pwc->setProperty('isVersionSeriesCheckedOut', true); | 127 | $pwc->setProperty('isVersionSeriesCheckedOut', true); |
| 124 | $userName = ''; | 128 | $userName = ''; |
| @@ -127,8 +131,8 @@ class CMISVersioningService { | @@ -127,8 +131,8 @@ class CMISVersioningService { | ||
| 127 | $userName = $user->getName(); | 131 | $userName = $user->getName(); |
| 128 | } | 132 | } |
| 129 | $pwc->setProperty('versionSeriesCheckedOutBy', $userName); | 133 | $pwc->setProperty('versionSeriesCheckedOutBy', $userName); |
| 130 | - $pwc->setProperty('versionSeriesCheckedOutId', $documentId); | ||
| 131 | - | 134 | + $pwc->setProperty('versionSeriesCheckedOutId', $objectId); |
| 135 | + | ||
| 132 | return $contentCopied; | 136 | return $contentCopied; |
| 133 | } | 137 | } |
| 134 | 138 | ||
| @@ -136,19 +140,18 @@ class CMISVersioningService { | @@ -136,19 +140,18 @@ class CMISVersioningService { | ||
| 136 | * 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" | 140 | * 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" |
| 137 | * | 141 | * |
| 138 | * @param string $repositoryId | 142 | * @param string $repositoryId |
| 139 | - * @param string $documentId | ||
| 140 | - * @param string $changeToken [optional] | 143 | + * @param string $objectId |
| 141 | */ | 144 | */ |
| 142 | // TODO exceptions: | 145 | // TODO exceptions: |
| 143 | // • versioningException - The repository MAY throw this exception if the object is a non-current Document Version. | 146 | // • versioningException - The repository MAY throw this exception if the object is a non-current Document Version. |
| 144 | - public function cancelCheckOut($repositoryId, $documentId, $changeToken = '') | 147 | + public function cancelCheckOut($repositoryId, $objectId) |
| 145 | { | 148 | { |
| 146 | - $documentId = CMISUtil::decodeObjectId($documentId, $typeId); | 149 | + $objectId = CMISUtil::decodeObjectId($objectId, $typeId); |
| 147 | 150 | ||
| 148 | /* re-generate PWC object */ | 151 | /* re-generate PWC object */ |
| 149 | // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). | 152 | // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). |
| 150 | try { | 153 | try { |
| 151 | - $pwc = new CMISDocumentObject($documentId, $this->ktapi); | 154 | + $pwc = new CMISDocumentObject($objectId, $this->ktapi); |
| 152 | } | 155 | } |
| 153 | catch (exception $e) { | 156 | catch (exception $e) { |
| 154 | throw new UpdateConflictException($e->getMessage()); | 157 | throw new UpdateConflictException($e->getMessage()); |
| @@ -159,10 +162,15 @@ class CMISVersioningService { | @@ -159,10 +162,15 @@ class CMISVersioningService { | ||
| 159 | throw new ConstraintViolationException('This document is not versionable and may not be checked out'); | 162 | throw new ConstraintViolationException('This document is not versionable and may not be checked out'); |
| 160 | } | 163 | } |
| 161 | 164 | ||
| 165 | + // check that this is the latest version | ||
| 166 | + if ($pwc->getProperty('isLatestVersion') != true) { | ||
| 167 | + throw new VersioningException('The document is not the latest version'); | ||
| 168 | + } | ||
| 169 | + | ||
| 162 | // TODO delete PWC - since we are not persisting the PWC this is not necessary at the moment | 170 | // TODO delete PWC - since we are not persisting the PWC this is not necessary at the moment |
| 163 | 171 | ||
| 164 | // cancel checkout | 172 | // cancel checkout |
| 165 | - $response = $this->ktapi->undo_document_checkout($documentId, 'CMIS Cancel Checkout Action', $sig_username, $sig_password); | 173 | + $response = $this->ktapi->undo_document_checkout($objectId, 'CMIS Cancel Checkout Action', $sig_username, $sig_password); |
| 166 | 174 | ||
| 167 | // if there was any error in cancelling the checkout | 175 | // if there was any error in cancelling the checkout |
| 168 | if ($response['status_code'] == 1) { | 176 | if ($response['status_code'] == 1) { |
| @@ -174,28 +182,35 @@ class CMISVersioningService { | @@ -174,28 +182,35 @@ class CMISVersioningService { | ||
| 174 | * Checks in a checked out document | 182 | * Checks in a checked out document |
| 175 | * | 183 | * |
| 176 | * @param string $repositoryId | 184 | * @param string $repositoryId |
| 177 | - * @param string $documentId | ||
| 178 | - * @param boolean $major | ||
| 179 | - * @param string $changeToken [optional] | 185 | + * @param string $objectId |
| 186 | + * @param boolean $major [optional] defaults to true | ||
| 180 | * @param array $properties [optional] | 187 | * @param array $properties [optional] |
| 181 | * @param contentStream $contentStream [optional] | 188 | * @param contentStream $contentStream [optional] |
| 182 | * @param string $checkinComment [optional] | 189 | * @param string $checkinComment [optional] |
| 183 | - * @return string $documentId | 190 | + * @param array $policies |
| 191 | + * @param array $addACEs | ||
| 192 | + * @param array $removeACEs | ||
| 193 | + * @return string $objectId | ||
| 184 | */ | 194 | */ |
| 185 | - // TODO Exceptions: | ||
| 186 | - // • versioningException - The repository MAY throw this exception if the object is a non-current Document Version | ||
| 187 | - public function checkIn($repositoryId, $documentId, $major, $contentStream = null, $changeToken = '', $properties = array(), $checkinComment = '') | 195 | + // NOTE For repositories that do NOT support the optional “capabilityPWCUpdatable” capability, the properties |
| 196 | + // and contentStream input parameters MUST be provided on the checkIn method for updates to happen as part | ||
| 197 | + // of checkIn. | ||
| 198 | + // NOTE Only those properties whose values are different than the original value of the object need to be submitted. | ||
| 199 | + // NOTE we are not actually doing anything with the properties at this time, only the content stream | ||
| 200 | + // TODO filename changes and anything else supported in web interface, possibly additional supported by CMIS clients | ||
| 201 | + public function checkIn($repositoryId, $objectId, $major = true, $properties = array(), $contentStream = null, | ||
| 202 | + $checkinComment = '', $policies = array(), $addACEs = array(), $removeACEs = array()) | ||
| 188 | { | 203 | { |
| 189 | - $documentId = CMISUtil::decodeObjectId($documentId, $typeId); | ||
| 190 | - | 204 | + $objectId = CMISUtil::decodeObjectId($objectId, $typeId); |
| 205 | + | ||
| 191 | // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). | 206 | // throw updateConflictException if the operation is attempting to update an object that is no longer current (as determined by the repository). |
| 192 | try { | 207 | try { |
| 193 | - $pwc = new CMISDocumentObject($documentId, $this->ktapi); | 208 | + $pwc = new CMISDocumentObject($objectId, $this->ktapi); |
| 194 | } | 209 | } |
| 195 | catch (exception $e) { | 210 | catch (exception $e) { |
| 196 | throw new UpdateConflictException($e->getMessage()); | 211 | throw new UpdateConflictException($e->getMessage()); |
| 197 | } | 212 | } |
| 198 | - | 213 | + |
| 199 | // throw exception if the object is not versionable | 214 | // throw exception if the object is not versionable |
| 200 | if (!$pwc->getAttribute('versionable')) { | 215 | if (!$pwc->getAttribute('versionable')) { |
| 201 | throw new ConstraintViolationException('This document is not versionable and may not be checked in'); | 216 | throw new ConstraintViolationException('This document is not versionable and may not be checked in'); |
| @@ -209,11 +224,17 @@ class CMISVersioningService { | @@ -209,11 +224,17 @@ class CMISVersioningService { | ||
| 209 | // if we can't get the type definition, then we can't store the content | 224 | // if we can't get the type definition, then we can't store the content |
| 210 | throw new StorageException($e->getMessage()); | 225 | throw new StorageException($e->getMessage()); |
| 211 | } | 226 | } |
| 212 | - | ||
| 213 | - if (($typeDefinition['attributes']['contentStreamAllowed'] == 'notAllowed') && !empty($contentStream)) { | 227 | + |
| 228 | + // if content stream is required (capabilityPWCUpdatability == false) and no content stream is supplied, | ||
| 229 | + // throw a ConstraintViolationException | ||
| 230 | + if (($typeDefinition['attributes']['contentStreamAllowed'] == 'required') && is_null($contentStream)) { | ||
| 231 | + throw new RuntimeException('This repository requires a content stream for document update on checkin. ' | ||
| 232 | + . 'Refusing to checkin an empty document'); | ||
| 233 | + } | ||
| 234 | + else if (($typeDefinition['attributes']['contentStreamAllowed'] == 'notAllowed') && !empty($contentStream)) { | ||
| 214 | throw new StreamNotSupportedException('Content Streams are not supported'); | 235 | throw new StreamNotSupportedException('Content Streams are not supported'); |
| 215 | } | 236 | } |
| 216 | - | 237 | + |
| 217 | // check that this is the latest version | 238 | // check that this is the latest version |
| 218 | if ($pwc->getProperty('isLatestVersion') != true) { | 239 | if ($pwc->getProperty('isLatestVersion') != true) { |
| 219 | throw new VersioningException('The document is not the latest version and cannot be checked in'); | 240 | throw new VersioningException('The document is not the latest version and cannot be checked in'); |
| @@ -221,15 +242,16 @@ class CMISVersioningService { | @@ -221,15 +242,16 @@ class CMISVersioningService { | ||
| 221 | 242 | ||
| 222 | // now do the checkin | 243 | // now do the checkin |
| 223 | $tempfilename = CMISUtil::createTemporaryFile($contentStream); | 244 | $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 | 245 | + $reason = 'CMIS object checkin'; |
| 246 | + $response = $this->ktapi->checkin_document($objectId, $pwc->getProperty('contentStreamFilename'), $reason, $tempfilename, $major, | ||
| 247 | + $sig_username, $sig_password); | ||
| 248 | + | ||
| 249 | + // if there was any error checking in | ||
| 228 | if ($response['status_code'] == 1) { | 250 | if ($response['status_code'] == 1) { |
| 229 | throw new RuntimeException('There was an error checking in the document: ' . $response['message']); | 251 | throw new RuntimeException('There was an error checking in the document: ' . $response['message']); |
| 230 | } | 252 | } |
| 231 | 253 | ||
| 232 | - return CMISUtil::encodeObjectId(DOCUMENT, $documentId); | 254 | + return CMISUtil::encodeObjectId(DOCUMENT, $objectId); |
| 233 | } | 255 | } |
| 234 | 256 | ||
| 235 | } | 257 | } |
webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php
| @@ -34,7 +34,7 @@ When POSTing an Atom Document, the atom fields take precedence over the CMIS pro | @@ -34,7 +34,7 @@ When POSTing an Atom Document, the atom fields take precedence over the CMIS pro | ||
| 34 | include_once CMIS_ATOM_LIB_FOLDER . 'RepositoryService.inc.php'; | 34 | include_once CMIS_ATOM_LIB_FOLDER . 'RepositoryService.inc.php'; |
| 35 | include_once CMIS_ATOM_LIB_FOLDER . 'NavigationService.inc.php'; | 35 | include_once CMIS_ATOM_LIB_FOLDER . 'NavigationService.inc.php'; |
| 36 | include_once CMIS_ATOM_LIB_FOLDER . 'ObjectService.inc.php'; | 36 | include_once CMIS_ATOM_LIB_FOLDER . 'ObjectService.inc.php'; |
| 37 | -include_once CMIS_ATOM_LIB_FOLDER . 'VersioningService.inc.php'; | 37 | +include_once CMIS_API . '/ktVersioningService.inc.php'; |
| 38 | include_once 'KT_cmis_atom_service_helper.inc.php'; | 38 | include_once 'KT_cmis_atom_service_helper.inc.php'; |
| 39 | 39 | ||
| 40 | // 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 | // 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. |
| @@ -157,6 +157,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { | @@ -157,6 +157,7 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { | ||
| 157 | $objectId = $this->params[2]; | 157 | $objectId = $this->params[2]; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | + // get object properties - todo send through original properties array and not modified version | ||
| 160 | $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->rawContent); | 161 | $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->rawContent); |
| 161 | $properties = array('name' => $title, 'summary' => $summary, 'objectTypeId' => $cmisObjectProperties['cmis:objectTypeId']); | 162 | $properties = array('name' => $title, 'summary' => $summary, 'objectTypeId' => $cmisObjectProperties['cmis:objectTypeId']); |
| 162 | 163 | ||
| @@ -188,7 +189,6 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { | @@ -188,7 +189,6 @@ class KT_cmis_atom_service_folder extends KT_cmis_atom_service { | ||
| 188 | 189 | ||
| 189 | $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt()); | 190 | $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt()); |
| 190 | 191 | ||
| 191 | - global $default; | ||
| 192 | $success = false; | 192 | $success = false; |
| 193 | $error = null; | 193 | $error = null; |
| 194 | if ($action == 'create') | 194 | if ($action == 'create') |
| @@ -430,7 +430,7 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service { | @@ -430,7 +430,7 @@ class KT_cmis_atom_service_document extends KT_cmis_atom_service { | ||
| 430 | 430 | ||
| 431 | $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); | 431 | $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); |
| 432 | 432 | ||
| 433 | - $VersioningService = new VersioningService(KT_cmis_atom_service_helper::getKt()); | 433 | + $VersioningService = new KTVersioningService(KT_cmis_atom_service_helper::getKt()); |
| 434 | 434 | ||
| 435 | // attempt delete | 435 | // attempt delete |
| 436 | $response = $VersioningService->deleteAllVersions($repositoryId, $this->params[0]); | 436 | $response = $VersioningService->deleteAllVersions($repositoryId, $this->params[0]); |
| @@ -491,13 +491,12 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service { | @@ -491,13 +491,12 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service { | ||
| 491 | 491 | ||
| 492 | $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); | 492 | $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); |
| 493 | 493 | ||
| 494 | - $VersioningService = new VersioningService(KT_cmis_atom_service_helper::getKt()); | 494 | + $VersioningService = new KTVersioningService(KT_cmis_atom_service_helper::getKt()); |
| 495 | 495 | ||
| 496 | $response = $VersioningService->cancelCheckout($repositoryId, $this->params[0]); | 496 | $response = $VersioningService->cancelCheckout($repositoryId, $this->params[0]); |
| 497 | 497 | ||
| 498 | - if (PEAR::isError($response)) | ||
| 499 | - { | ||
| 500 | - $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage()); | 498 | + if ($response['status_code'] == 1) { |
| 499 | + $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response['message']); | ||
| 501 | // Expose the responseFeed | 500 | // Expose the responseFeed |
| 502 | $this->responseFeed = $feed; | 501 | $this->responseFeed = $feed; |
| 503 | return null; | 502 | return null; |
| @@ -510,45 +509,41 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service { | @@ -510,45 +509,41 @@ class KT_cmis_atom_service_pwc extends KT_cmis_atom_service { | ||
| 510 | public function PUT_action() | 509 | public function PUT_action() |
| 511 | { | 510 | { |
| 512 | $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); | 511 | $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); |
| 513 | - | ||
| 514 | - $VersioningService = new VersioningService(KT_cmis_atom_service_helper::getKt()); | 512 | + $VersioningService = new KTVersioningService(KT_cmis_atom_service_helper::getKt()); |
| 515 | $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt()); | 513 | $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt()); |
| 514 | + | ||
| 515 | + // get object properties | ||
| 516 | + $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->rawContent); | ||
| 516 | 517 | ||
| 517 | // check for content stream | 518 | // check for content stream |
| 518 | - // NOTE this is a hack! will not work with CMISSpaces at least, probably not with any client except RestTest and similar | ||
| 519 | - // where we can manually modify the input | ||
| 520 | - // first we try for an atom content tag | ||
| 521 | - $content = KT_cmis_atom_service_helper::getAtomValues($this->rawContent, 'content'); | ||
| 522 | - if (!empty($content)) { | ||
| 523 | - $contentStream = $content; | ||
| 524 | - } | ||
| 525 | - // not found? try for a regular content tag | ||
| 526 | - else { | ||
| 527 | - $content = KT_cmis_atom_service_helper::findTag('content', $this->parsedXMLContent['@children'], null, false); | ||
| 528 | - $contentStream = $content['@value']; | ||
| 529 | - } | ||
| 530 | - | ||
| 531 | - // if we haven't found it now, the real hack begins - retrieve the EXISTING content and submit this as the contentStream | 519 | + $content = KT_cmis_atom_service_helper::getCmisContent($this->rawContent); |
| 520 | + // NOTE not sure about the text type, will need testing, most content will be base64 | ||
| 521 | + $cmisContent = (isset($content['cmisra:base64']) | ||
| 522 | + ? $content['cmisra:base64'] | ||
| 523 | + : ((isset($content['cmisra:text'])) | ||
| 524 | + ? $content['cmisra:text'] | ||
| 525 | + : null)); | ||
| 526 | + | ||
| 527 | + // if we haven't found it now, the hack begins - retrieve the EXISTING content and submit this as the contentStream | ||
| 532 | // this is needed because KnowledgeTree will not accept a checkin without a content stream but CMISSpaces (and possibly | 528 | // this is needed because KnowledgeTree will not accept a checkin without a content stream but CMISSpaces (and possibly |
| 533 | // 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) | 529 | // 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) |
| 534 | // NOTE that if the content is INTENDED to be empty this and all the above checks will FAIL! | 530 | // NOTE that if the content is INTENDED to be empty this and all the above checks will FAIL! |
| 535 | // FIXME this is horrible, terrible, ugly and bad! | 531 | // FIXME this is horrible, terrible, ugly and bad! |
| 536 | - if (empty($contentStream)) { | ||
| 537 | - $contentStream = base64_encode(KT_cmis_atom_service_helper::getContentStream($this, $ObjectService, $repositoryId)); | 532 | + if (empty($cmisContent)) { |
| 533 | + $cmisContent = base64_encode(KT_cmis_atom_service_helper::getContentStream($this, $ObjectService, $repositoryId)); | ||
| 538 | } | 534 | } |
| 539 | 535 | ||
| 540 | - // and if we don't have it by now, we give up...but leave the error to be generated by the underlying KnowledgeTree code | ||
| 541 | - | 536 | + // and if we don't have the content stream by now, we give up...but leave the error to be generated by the underlying KnowledgeTree code |
| 542 | // checkin function call | 537 | // checkin function call |
| 543 | // TODO dynamically detect version change type - leaving this for now as the CMIS clients tested do not appear to | 538 | // TODO dynamically detect version change type - leaving this for now as the CMIS clients tested do not appear to |
| 544 | // offer the choice to the user - perhaps it will turn out that this will come from somewhere else but for now | 539 | // offer the choice to the user - perhaps it will turn out that this will come from somewhere else but for now |
| 545 | // we assume minor version updates only | 540 | // we assume minor version updates only |
| 546 | $major = false; | 541 | $major = false; |
| 547 | - $response = $VersioningService->checkIn($repositoryId, $this->params[0], $major, $contentStream); | ||
| 548 | - | ||
| 549 | - if (PEAR::isError($response)) | ||
| 550 | - { | ||
| 551 | - $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response->getMessage()); | 542 | + $checkinComment = ''; |
| 543 | + $response = $VersioningService->checkIn($repositoryId, $this->params[0], $major, $cmisObjectProperties, $cmisContent, $checkinComment); | ||
| 544 | + | ||
| 545 | + if ($response['status_code'] == 1) { | ||
| 546 | + $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $response['message']); | ||
| 552 | // Expose the responseFeed | 547 | // Expose the responseFeed |
| 553 | $this->responseFeed = $feed; | 548 | $this->responseFeed = $feed; |
| 554 | return null; | 549 | return null; |
| @@ -630,7 +625,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | @@ -630,7 +625,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | ||
| 630 | { | 625 | { |
| 631 | $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); | 626 | $repositoryId = KT_cmis_atom_service_helper::getRepositoryId($RepositoryService); |
| 632 | 627 | ||
| 633 | - $VersioningService = new VersioningService(KT_cmis_atom_service_helper::getKt()); | 628 | + $VersioningService = new KTVersioningService(KT_cmis_atom_service_helper::getKt()); |
| 634 | $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt()); | 629 | $ObjectService = new ObjectService(KT_cmis_atom_service_helper::getKt()); |
| 635 | 630 | ||
| 636 | $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->rawContent); | 631 | $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->rawContent); |
| @@ -646,8 +641,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | @@ -646,8 +641,7 @@ class KT_cmis_atom_service_checkedout extends KT_cmis_atom_service { | ||
| 646 | 641 | ||
| 647 | $response = $VersioningService->checkOut($repositoryId, $cmisObjectProperties['cmis:objectId']); | 642 | $response = $VersioningService->checkOut($repositoryId, $cmisObjectProperties['cmis:objectId']); |
| 648 | 643 | ||
| 649 | - if (PEAR::isError($response)) | ||
| 650 | - { | 644 | + if ($response['status_code'] == 1) { |
| 651 | $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, 'No object was specified for checkout'); | 645 | $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, 'No object was specified for checkout'); |
| 652 | // Expose the responseFeed | 646 | // Expose the responseFeed |
| 653 | $this->responseFeed = $feed; | 647 | $this->responseFeed = $feed; |
webservice/atompub/cmis/index.php
| @@ -49,6 +49,7 @@ define('KT_ATOM_LIB_FOLDER', '../../classes/atompub/'); | @@ -49,6 +49,7 @@ define('KT_ATOM_LIB_FOLDER', '../../classes/atompub/'); | ||
| 49 | define('CMIS_APP_BASE_URI', trim(KT_APP_BASE_URI, '/')); | 49 | define('CMIS_APP_BASE_URI', trim(KT_APP_BASE_URI, '/')); |
| 50 | define('CMIS_APP_SYSTEM_URI', KT_APP_SYSTEM_URI); | 50 | define('CMIS_APP_SYSTEM_URI', KT_APP_SYSTEM_URI); |
| 51 | define('CMIS_ATOM_LIB_FOLDER', trim(KT_ATOM_LIB_FOLDER, '/') . '/cmis/'); | 51 | define('CMIS_ATOM_LIB_FOLDER', trim(KT_ATOM_LIB_FOLDER, '/') . '/cmis/'); |
| 52 | +define('CMIS_API', KT_LIB_DIR . '/api/ktcmis'); | ||
| 52 | 53 | ||
| 53 | /** | 54 | /** |
| 54 | * Check Realm Authentication | 55 | * Check Realm Authentication |
webservice/classes/atompub/cmis/ObjectService.inc.php
| @@ -89,11 +89,12 @@ class ObjectService extends KTObjectService { | @@ -89,11 +89,12 @@ class ObjectService extends KTObjectService { | ||
| 89 | * | 89 | * |
| 90 | * @param string $repositoryId | 90 | * @param string $repositoryId |
| 91 | * @param string $objectId | 91 | * @param string $objectId |
| 92 | + * @param string $streamId [optional for documents] Specifies the rendition to retrieve if not original document | ||
| 92 | * @return string $contentStream (binary or text data) | 93 | * @return string $contentStream (binary or text data) |
| 93 | */ | 94 | */ |
| 94 | - function getContentStream($repositoryId, $objectId) | 95 | + function getContentStream($repositoryId, $objectId, $streamId = null) |
| 95 | { | 96 | { |
| 96 | - $result = parent::getContentStream($repositoryId, $objectId); | 97 | + $result = parent::getContentStream($repositoryId, $objectId, $streamId); |
| 97 | 98 | ||
| 98 | if ($result['status_code'] == 0) { | 99 | if ($result['status_code'] == 0) { |
| 99 | return $result['results']; | 100 | return $result['results']; |
webservice/classes/atompub/cmis/VersioningService.inc.php
| @@ -27,75 +27,6 @@ class VersioningService extends KTVersioningService { | @@ -27,75 +27,6 @@ class VersioningService extends KTVersioningService { | ||
| 27 | return new PEAR_Error($result['message']); | 27 | return new PEAR_Error($result['message']); |
| 28 | } | 28 | } |
| 29 | } | 29 | } |
| 30 | - | ||
| 31 | - /** | ||
| 32 | - * Checks out a document and creates the PWC (Private Working Copy) which will represent the checked out document | ||
| 33 | - * | ||
| 34 | - * @param string $repositoryId | ||
| 35 | - * @param string $documentId | ||
| 36 | - * @param string $changeToken [optional] | ||
| 37 | - * @return array results | ||
| 38 | - */ | ||
| 39 | - // TODO set up delivery of content stream? or is that up to the CMIS client? | ||
| 40 | - public function checkOut($repositoryId, $documentId, $changeToken = '') | ||
| 41 | - { | ||
| 42 | - $result = parent::checkOut($repositoryId, $documentId, $changeToken); | ||
| 43 | - | ||
| 44 | - if ($result['status_code'] == 0) { | ||
| 45 | - return $result['results']; | ||
| 46 | - } | ||
| 47 | - else { | ||
| 48 | - return new PEAR_Error($result['message']); | ||
| 49 | - } | ||
| 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 | - } | ||
| 75 | - | ||
| 76 | - /** | ||
| 77 | - * Checks in a checked out document | ||
| 78 | - * | ||
| 79 | - * @param string $repositoryId | ||
| 80 | - * @param string $documentId | ||
| 81 | - * @param boolean $major | ||
| 82 | - * @param string $changeToken [optional] | ||
| 83 | - * @param array $properties [optional] | ||
| 84 | - * @param contentStream $contentStream [optional] | ||
| 85 | - * @param string $checkinComment [optional] | ||
| 86 | - * @return string $documentId | ||
| 87 | - */ | ||
| 88 | - public function checkIn($repositoryId, $documentId, $major, $contentStream = null, $changeToken = '', $properties = array(), $checkinComment = '') | ||
| 89 | - { | ||
| 90 | - $result = parent::checkIn($repositoryId, $documentId, $major, $contentStream, $changeToken, $properties, $checkinComment); | ||
| 91 | - | ||
| 92 | - if ($result['status_code'] == 0) { | ||
| 93 | - return $result['results']; | ||
| 94 | - } | ||
| 95 | - else { | ||
| 96 | - return new PEAR_Error($result['message']); | ||
| 97 | - } | ||
| 98 | - } | ||
| 99 | 30 | ||
| 100 | } | 31 | } |
| 101 | 32 |