Add relationship support to cmislib browser binding to close #CMIS-1008.


git-svn-id: https://svn.apache.org/repos/asf/chemistry/cmislib/trunk@1802742 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/cmislib/browser/binding.py b/src/cmislib/browser/binding.py
index d980d54..7788d15 100644
--- a/src/cmislib/browser/binding.py
+++ b/src/cmislib/browser/binding.py
@@ -452,7 +452,26 @@
 
         """
 
-        pass
+        if not self.allowableActions['canCreateRelationship']:
+            raise CmisException('Not allowed to create a relationship')
+        url = self._repository.getRepositoryUrl()
+        props = {
+            'cmisaction': 'createRelationship',
+        }
+
+        setProps({
+            'cmis:sourceId': self.getObjectId(),
+            'cmis:targetId': targetObj.getObjectId(),
+            'cmis:objectTypeId': relTypeId
+        }, props)
+
+        # invoke the URL
+        result = self._cmisClient.binding.post(url.encode('utf-8'),
+                                               safe_urlencode(props),
+                                               'application/x-www-form-urlencoded',
+                                               self._cmisClient.username,
+                                               self._cmisClient.password)
+        return getSpecializedObject(BrowserCmisObject(self._cmisClient, self._repository, data=result))
 
     def getRelationships(self, **kwargs):
 
@@ -477,7 +496,13 @@
          - includeAllowableActions
         """
 
-        pass
+        byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=relationships"
+        result = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
+                                              self._cmisClient.username,
+                                              self._cmisClient.password,
+                                              **kwargs)
+        # return the result set
+        return BrowserResultSet(self._cmisClient, self._repository, result, serializer=RelationShipsSerializer())
 
     def removePolicy(self, policyId):
 
@@ -1400,7 +1425,7 @@
          - removeACEs
         """
 
-        pass
+        return sourceObj.createRelationship(targetObj, relType)
 
     def createPolicy(self, properties):
         """
@@ -2358,7 +2383,7 @@
         return [self.properties['cmis:path']]
 
 
-class BrowserRelationship(CmisObject):
+class BrowserRelationship(BrowserCmisObject):
 
     """
     Defines a relationship object between two :class:`CmisObjects` objects
@@ -2369,16 +2394,16 @@
         """
         Returns the :class:`CmisId` on the source side of the relationship.
         """
-        # TODO need to implement
-        pass
+
+        return BrowserCmisId(self.properties['cmis:sourceId'])
 
     def getTargetId(self):
 
         """
         Returns the :class:`CmisId` on the target side of the relationship.
         """
-        # TODO need to implement
-        pass
+
+        return BrowserCmisId(self.properties['cmis:targetId'])
 
     def getSource(self):
 
@@ -2386,8 +2411,9 @@
         Returns an instance of the appropriate child-type of :class:`CmisObject`
         for the source side of the relationship.
         """
-        # TODO need to implement
-        pass
+
+        sourceId = self.getSourceId()
+        return getSpecializedObject(self._repository.getObject(sourceId))
 
     def getTarget(self):
 
@@ -2395,8 +2421,9 @@
         Returns an instance of the appropriate child-type of :class:`CmisObject`
         for the target side of the relationship.
         """
-        # TODO need to implement
-        pass
+
+        targetId = self.getTargetId()
+        return getSpecializedObject(self._repository.getObject(targetId))
 
     sourceId = property(getSourceId)
     targetId = property(getTargetId)
@@ -3271,6 +3298,24 @@
         return entries
 
 
+class RelationShipsSerializer(object):
+
+    """
+    Responsible for serializing lists of relationships.
+    """
+
+    def fromJSON(self, client, repo, jsonObj):
+        """Transforms from JSON to the object."""
+        entries = []
+        for obj in jsonObj['objects']:
+            cmisObject = getSpecializedObject(BrowserCmisObject(client,
+                                                                repo,
+                                                                data=obj))
+            entries.append(cmisObject)
+
+        return entries
+
+
 class VersionsSerializer(object):
 
     """
diff --git a/src/tests/cmislibtest.py b/src/tests/cmislibtest.py
index e7f19cd..9f336a9 100644
--- a/src/tests/cmislibtest.py
+++ b/src/tests/cmislibtest.py
@@ -1334,6 +1334,25 @@
         paths = testDoc.getPaths()
         self.assertTrue(len(paths) >= 1)
 
+    def testRelationship(self):
+        testDoc = self._testFolder.createDocument('testdoc')
+        testDoc2 = self._testFolder.createDocument('testdoc2')
+        relations = testDoc.getRelationships(relationshipDirection="either")
+        self.assertEqual(0, len(relations))
+        if not testDoc.getAllowableActions().get('canCreateRelationship'):
+            print 'createRelationship not supported, skipping'
+            return
+        else:
+            print(testDoc.getAllowableActions())
+        relation = testDoc.createRelationship(testDoc2, 'R:cmis:relationship')
+        self.assertEqual(testDoc.getObjectId(), relation.source.getObjectId())
+        self.assertEqual(testDoc2.getObjectId(), relation.target.getObjectId())
+        relations = testDoc.getRelationships()
+        self.assertEqual(1, len(relations))
+        relation = relations[0]
+        self.assertEqual(testDoc.getObjectId(), relation.source.getObjectId())
+        self.assertEqual(testDoc2.getObjectId(), relation.target.getObjectId())
+
     def testRenditions(self):
         """Get the renditions for a document"""
         if not self._repo.getCapabilities().has_key('Renditions'):