cmislib browser binding createDocument and createDocumentFromString now working
git-svn-id: https://svn.apache.org/repos/asf/chemistry/cmislib/trunk@1592276 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/cmislib/__init__.py b/src/cmislib/__init__.py
index 08ee007..f865650 100644
--- a/src/cmislib/__init__.py
+++ b/src/cmislib/__init__.py
@@ -20,7 +20,8 @@
Define package contents so that they are easy to import.
"""
-from model import CmisClient
-from domain import Repository, Folder
+from cmislib.model import CmisClient
+from cmislib.domain import Repository, Folder
+from cmislib.cmis_services import Binding, RepositoryServiceIfc
-__all__ = ["CmisClient", "Repository", "Folder"]
+__all__ = ["Binding", "CmisClient", "RepositoryServiceIfc", "Repository", "Folder"]
diff --git a/src/cmislib/atompub/__init__.py b/src/cmislib/atompub/__init__.py
new file mode 100644
index 0000000..6e30c70
--- /dev/null
+++ b/src/cmislib/atompub/__init__.py
@@ -0,0 +1 @@
+__author__ = 'jpotts'
diff --git a/src/cmislib/atompub_binding.py b/src/cmislib/atompub/binding.py
similarity index 99%
rename from src/cmislib/atompub_binding.py
rename to src/cmislib/atompub/binding.py
index 43aea85..5ba1de5 100644
--- a/src/cmislib/atompub_binding.py
+++ b/src/cmislib/atompub/binding.py
@@ -20,15 +20,14 @@
Module containing the Atom Pub binding-specific objects used to work with a CMIS
provider.
"""
-from cmis_services import RepositoryServiceIfc
-from cmis_services import Binding
-from domain import CmisId, CmisObject, ObjectType, Property, ACL, ACE, ChangeEntry, ResultSet, Rendition
-from net import RESTService as Rest
-from exceptions import CmisException, \
+from cmislib.cmis_services import Binding, RepositoryServiceIfc
+from cmislib.domain import CmisId, CmisObject, ObjectType, Property, ACL, ACE, ChangeEntry, ResultSet, Rendition
+from cmislib.net import RESTService as Rest
+from cmislib.exceptions import CmisException, \
ObjectNotFoundException, InvalidArgumentException, \
NotSupportedException
-from util import parseDateTimeValue
-import messages
+from cmislib.util import multiple_replace, parsePropValue, parseBoolValue, toCMISValue, parseDateTimeValue
+import cmislib.messages
from urllib import quote
from urlparse import urlparse, urlunparse
@@ -39,7 +38,6 @@
import StringIO
import logging
from xml.dom import minidom
-from util import multiple_replace, parsePropValue, parseBoolValue, toCMISValue
moduleLogger = logging.getLogger('cmislib.atompub_binding')
@@ -1882,7 +1880,7 @@
If the types collection is specified, the method returns the result of
`getTypeDefinitions` and ignores any optional params passed in.
- >>> from cmislib.atompub_binding import TYPES_COLL
+ >>> from cmislib.atompub.atompub_binding import TYPES_COLL
>>> types = repo.getCollection(TYPES_COLL)
>>> len(types)
4
@@ -1892,7 +1890,7 @@
Otherwise, the collection URL is invoked, and a :class:`ResultSet` is
returned.
- >>> from cmislib.atompub_binding import CHECKED_OUT_COLL
+ >>> from cmislib.atompub.atompub_binding import CHECKED_OUT_COLL
>>> resultSet = repo.getCollection(CHECKED_OUT_COLL)
>>> len(resultSet.getResults())
1
@@ -1917,7 +1915,7 @@
Returns the link HREF from the specified collectionType
('checkedout', for example).
- >>> from cmislib.atompub_binding import CHECKED_OUT_COLL
+ >>> from cmislib.atompub.atompub_binding import CHECKED_OUT_COLL
>>> repo.getCollectionLink(CHECKED_OUT_COLL)
u'http://localhost:8080/alfresco/s/cmis/checkedout'
@@ -3189,7 +3187,7 @@
"""
Gets the HREF for the link element with the specified rel and linkType.
- >>> from cmislib.atompub_binding import ATOM_XML_FEED_TYPE
+ >>> from cmislib.atompub.atompub_binding import ATOM_XML_FEED_TYPE
>>> docType.getLink('down', ATOM_XML_FEED_TYPE)
u'http://localhost:8080/alfresco/s/cmis/type/cmis:document/children'
"""
diff --git a/src/cmislib/browser/__init__.py b/src/cmislib/browser/__init__.py
new file mode 100644
index 0000000..6e30c70
--- /dev/null
+++ b/src/cmislib/browser/__init__.py
@@ -0,0 +1 @@
+__author__ = 'jpotts'
diff --git a/src/cmislib/browser_binding.py b/src/cmislib/browser/binding.py
similarity index 95%
rename from src/cmislib/browser_binding.py
rename to src/cmislib/browser/binding.py
index 3154c46..9fa215b 100644
--- a/src/cmislib/browser_binding.py
+++ b/src/cmislib/browser/binding.py
@@ -20,20 +20,20 @@
Module containing the browser binding-specific objects used to work with a CMIS
provider.
"""
-from cmis_services import RepositoryServiceIfc
-from cmis_services import Binding
-from net import RESTService as Rest
-from exceptions import CmisException, RuntimeException, ObjectNotFoundException
-from domain import CmisId, CmisObject, Repository, Relationship, Policy, ObjectType, Property, Folder, Document, ACL, ACE, ChangeEntry, ResultSet, ChangeEntryResultSet, Rendition
-from util import parsePropValueByType, parseBoolValue
+from cmislib.cmis_services import Binding, RepositoryServiceIfc
+from cmislib.domain import CmisId, CmisObject, Repository, Relationship, Policy, ObjectType, Property, Folder, Document, ACL, ACE, ChangeEntry, ResultSet, ChangeEntryResultSet, Rendition
+from cmislib.exceptions import CmisException, RuntimeException, ObjectNotFoundException
+from cmislib.net import RESTService as Rest
+from cmislib.util import parsePropValueByType, parseBoolValue
import json
-import StringIO
import logging
+import StringIO
+import time
from urllib import urlencode, quote
CMIS_FORM_TYPE = 'application/x-www-form-urlencoded;charset=utf-8'
-moduleLogger = logging.getLogger('cmislib.browser_binding')
+moduleLogger = logging.getLogger('cmislib.browser.binding')
class BrowserBinding(Binding):
def __init__(self, **kwargs):
@@ -1155,7 +1155,19 @@
<cmislib.model.Document object at 0x101352ed0>
"""
- pass
+ # if you didn't pass in a parent folder
+ if parentFolder is None:
+ # if the repository doesn't require fileable objects to be filed
+ if self.getCapabilities()['Unfiling']:
+ # has not been implemented
+ #postUrl = self.getCollectionLink(UNFILED_COLL)
+ raise NotImplementedError
+ else:
+ # this repo requires fileable objects to be filed
+ raise InvalidArgumentException
+
+ return parentFolder.createDocument(name, properties, StringIO.StringIO(contentString),
+ contentType, contentEncoding)
def createDocument(self,
name,
@@ -1189,7 +1201,47 @@
- removeACEs
"""
- pass
+ # if you didn't pass in a parent folder
+ if parentFolder is None:
+ # if the repository doesn't require fileable objects to be filed
+ if self.getCapabilities()['Unfiling']:
+ # has not been implemented
+ raise NotImplementedError
+ else:
+ # this repo requires fileable objects to be filed
+ raise InvalidArgumentException
+
+ # get the root folder URL
+ createDocUrl = self.getRootFolderUrl()
+
+ props = {"objectId" : parentFolder.id,
+ "cmisaction" : "createDocument",
+ "propertyId[0]" : "cmis:name",
+ "propertyValue[0]" : name}
+
+ props["propertyId[1]"] = "cmis:objectTypeId"
+ if properties.has_key('cmis:objectTypeId'):
+ props["propertyValue[1]"] = properties['cmis:objectTypeId']
+ else:
+ props["propertyValue[1]"] = "cmis:document"
+
+ propCount = 2
+ for prop in properties:
+ props["propertyId[%s]" % propCount] = prop.key
+ props["propertyValue[%s]" % propCount] = prop
+ propCount += 1
+
+ contentType, body = encode_multipart_formdata(props, contentFile, contentType)
+
+ # invoke the URL
+ result = self._cmisClient.binding.post(createDocUrl.encode('utf-8'),
+ body,
+ contentType,
+ self._cmisClient.username,
+ self._cmisClient.password)
+
+ # return the result set
+ return BrowserDocument(self._cmisClient, self, data=result)
def createDocumentFromSource(self,
sourceId,
@@ -1783,7 +1835,7 @@
of cmis:path with the relativePathSegment.
"""
- byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=parents"
+ byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=parents&includerelativepathsegment=true"
result = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
self._cmisClient.username,
self._cmisClient.password)
@@ -1793,6 +1845,7 @@
#TODO why is the call to getObjectParents() made if it isn't used?
for res in result:
path = res['object']['properties']['cmis:path']['value']
+ logging.debug(path)
relativePathSegment = res['relativePathSegment']
# concat with a slash
@@ -1881,39 +1934,12 @@
>>> testFolder.createDocumentFromString('testdoc3', contentString='hello, world', contentType='text/plain')
"""
- # get the root folder URL
- createDocUrl = self._repository.getRootFolderUrl()
-
- props = {"objectId" : self.id,
- "cmisaction" : "createDocument",
- "propertyId[0]" : "cmis:name",
- "propertyValue[0]" : name}
-
- props["propertyId[1]"] = "cmis:objectTypeId"
- if properties.has_key('cmis:objectTypeId'):
- props["propertyValue[1]"] = properties['cmis:objectTypeId']
- else:
- props["propertyValue[1]"] = "cmis:document"
-
- propCount = 2
- for prop in properties:
- props["propertyId[%s]" % propCount] = prop.key
- props["propertyValue[%s]" % propCount] = prop
- propCount += 1
-
- #TODO this isn't working at the moment
- props["content"] = contentString
-
- # invoke the URL
- result = self._cmisClient.binding.post(createDocUrl.encode('utf-8'),
- urlencode(props),
- 'application/x-www-form-urlencoded',
- self._cmisClient.username,
- self._cmisClient.password)
-
- # return the result set
- return BrowserDocument(self._cmisClient, self._repository, data=result)
-
+ return self._repository.createDocumentFromString(name,
+ properties,
+ self,
+ contentString,
+ contentType,
+ contentEncoding)
def createDocument(self, name, properties={}, contentFile=None,
contentType=None, contentEncoding=None):
@@ -1956,40 +1982,12 @@
- removeACEs
"""
- #TODO work in progress
-
- # get the root folder URL
- createDocUrl = self._repository.getRootFolderUrl()
-
- props = {"objectId" : self.id,
- "cmisaction" : "createDocument",
- "propertyId[0]" : "cmis:name",
- "propertyValue[0]" : name}
-
- props["propertyId[1]"] = "cmis:objectTypeId"
- if properties.has_key('cmis:objectTypeId'):
- pass
- else:
- props["propertyValue[1]"] = "cmis:document"
-
- propCount = 2
- for prop in properties:
- props["propertyId[%s]" % propCount] = prop
- props["propertyValue[%s]" % propCount] = properties[prop]
- propCount += 1
-
- #TODO this isn't working at the moment
- props["content"] = 'this is a test'
-
- # invoke the URL
- result = self._cmisClient.binding.post(createDocUrl.encode('utf-8'),
- urlencode(props),
- 'application/x-www-form-urlencoded',
- self._cmisClient.username,
- self._cmisClient.password)
-
- # return the result set
- return BrowserDocument(self._cmisClient, self._repository, data=result)
+ return self._repository.createDocument(name,
+ properties,
+ self,
+ contentFile,
+ contentType,
+ contentEncoding)
def getChildren(self, **kwargs):
@@ -2896,3 +2894,36 @@
# specify baseTypeId) or if the type isn't one of the known base
# types, give the object back
return obj
+
+def encode_multipart_formdata(fields, file, contentType):
+ """
+ fields is a sequence of (name, value) elements for regular form fields.
+ files is a sequence of (name, filename, value) elements for data to be uploaded as files
+ Return (content_type, body) ready for httplib.HTTP instance
+ """
+ boundary = 'aPacHeCheMIStrycMisLIb%s' % (int(time.time()))
+ crlf = '\r\n'
+ L = []
+ fileName = None
+ for (key, value) in fields.iteritems():
+ if (key == 'cmis:name'):
+ fileName = value
+ L.append('--' + boundary)
+ L.append('Content-Disposition: form-data; name="%s"' % key)
+ L.append('Content-Type: text/plain; charset=utf-8')
+ L.append('')
+ L.append(value)
+
+ if file:
+ L.append('--' + boundary)
+ L.append('Content-Disposition: form-data; name="%s"; filename=%s' % ('content', fileName))
+ L.append('Content-Type: %s' % contentType)
+ L.append('Content-Transfer-Encoding: binary')
+ L.append('')
+ L.append(file.read()) # content of file goes here
+
+ L.append('--' + boundary + '--')
+ L.append('')
+ body = crlf.join(L)
+ content_type = 'multipart/form-data; boundary=%s' % boundary
+ return content_type, body
\ No newline at end of file
diff --git a/src/cmislib/browser/serializers.py b/src/cmislib/browser/serializers.py
new file mode 100644
index 0000000..c92ec7b
--- /dev/null
+++ b/src/cmislib/browser/serializers.py
@@ -0,0 +1,14 @@
+import json
+
+from cmislib.browser.binding import BrowserFolder
+
+
+class FolderSerializer(object):
+ def toJSON(self, obj):
+ pass
+
+ def fromJSON(self, client, repo, jsonString):
+ obj = json.loads(jsonString)
+ objectId = obj['succinctProperties']['cmis:objectId']
+ folder = BrowserFolder(client, repo, objectId, properties=obj['succinctProperties'])
+ return folder
\ No newline at end of file
diff --git a/src/cmislib/cmis_services.py b/src/cmislib/cmis_services.py
index a6e09c0..5c0e107 100644
--- a/src/cmislib/cmis_services.py
+++ b/src/cmislib/cmis_services.py
@@ -19,7 +19,7 @@
"""
Module containing the base Binding class and other service objects.
"""
-from exceptions import CmisException, RuntimeException, \
+from cmislib.exceptions import CmisException, RuntimeException, \
ObjectNotFoundException, InvalidArgumentException, \
PermissionDeniedException, NotSupportedException, \
UpdateConflictException
diff --git a/src/cmislib/domain.py b/src/cmislib/domain.py
index a933434..b7b5327 100644
--- a/src/cmislib/domain.py
+++ b/src/cmislib/domain.py
@@ -957,7 +957,7 @@
If the types collection is specified, the method returns the result of
`getTypeDefinitions` and ignores any optional params passed in.
- >>> from cmislib.atompub_binding import TYPES_COLL
+ >>> from cmislib.atompub.atompub_binding import TYPES_COLL
>>> types = repo.getCollection(TYPES_COLL)
>>> len(types)
4
@@ -967,7 +967,7 @@
Otherwise, the collection URL is invoked, and a :class:`ResultSet` is
returned.
- >>> from cmislib.atompub_binding import CHECKED_OUT_COLL
+ >>> from cmislib.atompub.atompub_binding import CHECKED_OUT_COLL
>>> resultSet = repo.getCollection(CHECKED_OUT_COLL)
>>> len(resultSet.getResults())
1
@@ -1766,7 +1766,7 @@
"""
Gets the HREF for the link element with the specified rel and linkType.
- >>> from cmislib.atompub_binding import ATOM_XML_FEED_TYPE
+ >>> from cmislib.atompub.atompub_binding import ATOM_XML_FEED_TYPE
>>> docType.getLink('down', ATOM_XML_FEED_TYPE)
u'http://localhost:8080/alfresco/s/cmis/type/cmis:document/children'
"""
diff --git a/src/cmislib/model.py b/src/cmislib/model.py
index a17df1b..5e77c32 100644
--- a/src/cmislib/model.py
+++ b/src/cmislib/model.py
@@ -21,11 +21,12 @@
keeping track of connection information. The name 'model' is no longer
really appropriate, but it is kept for backwards compatibility.
"""
-from atompub_binding import AtomPubBinding
-from cmis_services import Binding
-from domain import CmisObject, Repository
import logging
+from atompub.binding import AtomPubBinding
+from cmis_services import Binding
+
+
moduleLogger = logging.getLogger('cmislib.model')
class CmisClient(object):