ensure that we change the ids of elements when copying/creating a new renkan
authorymh <ymh.work@gmail.com>
Wed, 29 Jun 2016 23:11:56 +0200
changeset 626 112912309726
parent 625 4d67ae41b9b3
child 627 aa895db6eb08
ensure that we change the ids of elements when copying/creating a new renkan
server/python/django2/renkanmanager/api/views.py
server/python/django2/renkanmanager/models.py
server/python/django2/renkanmanager/serializers.py
server/python/django2/renkanmanager/tests/test_models.py
server/python/django2/renkanmanager/tests/test_revision_copy.json
--- a/server/python/django2/renkanmanager/api/views.py	Wed Jun 29 22:48:10 2016 +0200
+++ b/server/python/django2/renkanmanager/api/views.py	Wed Jun 29 23:11:56 2016 +0200
@@ -85,11 +85,9 @@
                 return Response({'detail': 'Workspace '+workspace_guid+' does not exist'}, status=status.HTTP_404_NOT_FOUND)
             create_data["workspace_id"] = workspace_guid
         serializer = RenkanSerializer(data=create_data)
-        logger.debug("BEFORE SERIALIZER VALID %r", create_data)
         if serializer.is_valid():
             creator = request.user if request.user and not request.user.is_anonymous() else None
             serializer.save(creator=creator)
-            logger.debug("AFTER SAVE SERIALIZER DATA %r", serializer.data)
             return Response(serializer.data, status=status.HTTP_201_CREATED, content_type='application/json')
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
--- a/server/python/django2/renkanmanager/models.py	Wed Jun 29 22:48:10 2016 +0200
+++ b/server/python/django2/renkanmanager/models.py	Wed Jun 29 23:11:56 2016 +0200
@@ -16,6 +16,39 @@
 logger = logging.getLogger(__name__)
 auth_user_model = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
 
+# Copy the content of a révision.
+# This will return a map (not a serialized) to allow further treatment
+# This changes the ids of the project, nodes, views and edges but NOT users
+#
+def content_copy(content_str): #TODO: ??? Extract this in another class, like a RevisionManager ???
+    node_ids_map = {}
+    content = json.loads(content_str)
+
+    content['id'] = str(uuid.uuid4())
+
+    #nodes
+    for node in content.get('nodes', []):
+        id_key = 'id' if 'id' in node else '_id'
+        node_ids_map[node[id_key]] = node['id'] = str(uuid.uuid4())
+        node.pop('_id', None)
+
+    for edge in content.get('edges', []):
+        edge['id'] = str(uuid.uuid4())
+        edge.pop('_id', None)
+        edge['from'] = node_ids_map[edge['from']]
+        edge['to'] = node_ids_map[edge['to']]
+
+    for view in content.get('views', []):
+        view['id'] = str(uuid.uuid4())
+        view.pop('_id', None)
+        view['hidden_nodes'] = [ node_ids_map[n] for n in view.get('hidden_nodes', [])]
+
+    for user in content.get('users', []):
+        if '_id' in user:
+            user['id'] = user.pop('_id')
+
+    return content
+
 class Workspace(models.Model):
 
     workspace_guid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, blank=False, null=False)
@@ -60,7 +93,8 @@
         initial_revision.creator = creator
         initial_revision.last_updated_by = creator
         if new_renkan_content:
-            new_renkan_content_dict = json.loads(new_renkan.validate_json_content(new_renkan_content))
+            new_renkan_content_dict = content_copy(new_renkan.validate_json_content(new_renkan_content))
+            new_renkan_content_dict["id"] = str(new_renkan.renkan_guid)
             new_renkan_content_dict["created"] = str(creation_date)
             new_renkan_content_dict["updated"] = str(creation_date)
         else:
--- a/server/python/django2/renkanmanager/serializers.py	Wed Jun 29 22:48:10 2016 +0200
+++ b/server/python/django2/renkanmanager/serializers.py	Wed Jun 29 23:11:56 2016 +0200
@@ -47,7 +47,6 @@
         """
             Method to create a new Renkan (and its first revision)
         """
-        logger.debug("RENKANSERIALIZER %r", validated_data)
         creator = validated_data.get('creator')
         workspace_obj = validated_data.get('workspace', None)
         source_revision_obj = validated_data.get('source_revision', None)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/python/django2/renkanmanager/tests/test_models.py	Wed Jun 29 23:11:56 2016 +0200
@@ -0,0 +1,84 @@
+import json,os
+
+from django.test import TestCase
+from renkanmanager.models import content_copy
+from django.contrib.auth import get_user_model
+
+User = get_user_model()
+
+class ModelsTest(TestCase):
+
+    def setUp(self):
+        test_json_path = os.path.join(os.path.dirname(__file__), 'test_revision_copy.json')
+        with open(test_json_path) as json_file:
+            self.test_json = json_file.read()
+
+    def test_content_copy_call(self):
+        c_copy = content_copy(self.test_json)
+        self.assertIsNotNone(c_copy)
+
+    def test_content_copy_id_key(self):
+        c_copy = content_copy(self.test_json)
+        self.assertIn('id', c_copy)
+        self.assertNotIn('_id', c_copy)
+        for n in c_copy['nodes']:
+            self.assertIn('id', n)
+            self.assertNotIn('_id', n)
+        for u in c_copy['users']:
+            self.assertIn('id', u)
+            self.assertNotIn('_id', u)
+        for v in c_copy['views']:
+            self.assertIn('id', v)
+            self.assertNotIn('_id', v)
+        for e in c_copy['edges']:
+            self.assertIn('id', e)
+            self.assertNotIn('_id', e)
+
+    def test_content_copy_content(self):
+        c_copy = content_copy(self.test_json)
+        c_json = json.loads(self.test_json)
+
+        for k in (c_copy.keys() - ['nodes', 'users', 'views', 'edges', 'id']):
+            self.assertEquals(c_copy[k], c_json[k])
+
+        self.assertEquals(len(c_copy['nodes']), len(c_json['nodes']))
+        for node in c_copy['nodes']:
+            original_nodes = [ n for n in c_json['nodes'] if n['title'] == node['title'] ]
+            self.assertEquals(1,len(original_nodes))
+            for k in (node.keys() - ['id']):
+                self.assertEquals(node[k], original_nodes[0][k])
+
+        self.assertEquals(len(c_copy['edges']), len(c_json['edges']))
+        for edge in c_copy['edges']:
+            original_edges = [ e for e in c_json['edges'] if e['title'] == edge['title'] ]
+            self.assertEquals(1,len(original_edges))
+            orig_edge = original_edges[0]
+            for k in (edge.keys() - ['id', 'from', 'to']):
+                self.assertEquals(edge[k], orig_edge[k])
+            from_copy = [e for e in c_copy['nodes'] if e['id'] == edge['from']][0]
+            from_orig = [e for e in c_json['nodes'] if e['_id'] == orig_edge['from']][0]
+            self.assertEquals(from_copy['title'], from_orig['title'])
+
+            to_copy = [e for e in c_copy['nodes'] if e['id'] == edge['to']][0]
+            to_orig = [e for e in c_json['nodes'] if e['_id'] == orig_edge['to']][0]
+            self.assertEquals(to_copy['title'], to_orig['title'])
+
+        self.assertEquals(len(c_copy['users']), len(c_json['users']))
+        for user in c_copy['users']:
+            original_users = [ u for u in c_json['users'] if u['title'] == user['title'] ]
+            self.assertEquals(1,len(original_users))
+            for k in (user.keys() - ['id']):
+                self.assertEquals(user[k], original_users[0][k])
+
+        self.assertEquals(len(c_copy['views']), len(c_json['views']))
+        for view in c_copy['views']:
+            original_views = [ v for v in c_json['views'] if v['title'] == view['title'] ]
+            self.assertEquals(1,len(original_views))
+            orig_view = original_views[0]
+            for k in (view.keys() - ['id', 'hidden_nodes']):
+                self.assertEquals(view[k], orig_view[k])
+            self.assertEquals(len(view['hidden_nodes']), len(orig_view['hidden_nodes']))
+            copy_hidden_nodes_titles = sorted([ [n for n in c_copy['nodes'] if n['id'] == n_id][0]['title'] for n_id in view['hidden_nodes']])
+            orig_hidden_nodes_titles = sorted([ [n for n in c_json['nodes'] if n['_id'] == n_id][0]['title'] for n_id in orig_view['hidden_nodes']])
+
+            self.assertEquals(copy_hidden_nodes_titles, orig_hidden_nodes_titles)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/python/django2/renkanmanager/tests/test_revision_copy.json	Wed Jun 29 23:11:56 2016 +0200
@@ -0,0 +1,94 @@
+{
+    "users": [{
+        "_id": "admin",
+        "title": "root@iri.centrepompidou.fr",
+        "uri": "",
+        "description": "",
+        "color": "#666666"
+    }],
+    "nodes": [{
+        "_id": "node-2016-04-07-a9fe3711-8006-4a5d-b96a-0ab1630ee7de-0001",
+        "title": "test node 1",
+        "uri": "",
+        "description": "",
+        "position": {
+            "x": -109,
+            "y": -42.5
+        },
+        "image": "",
+        "style": {
+            "dash": false
+        },
+        "created_by": null,
+        "shape": "circle",
+        "type": "default"
+    }, {
+        "_id": "node-2016-06-21-6388a022-27c6-4f4a-8fb3-318b34d5ce9c-0001",
+        "title": "test node 2",
+        "uri": "",
+        "description": "",
+        "position": {
+            "x": -377,
+            "y": -14
+        },
+        "image": "",
+        "style": {
+            "dash": false
+        },
+        "created_by": null,
+        "shape": "circle",
+        "type": "default"
+    }, {
+        "_id": "node-2016-06-21-80cce7b7-030f-45f0-bb04-f8a771faee5f-0001",
+        "title": "test node 3",
+        "uri": "",
+        "description": "",
+        "position": {
+            "x": -253.21838623008796,
+            "y": -66.22059428680411
+        },
+        "image": "",
+        "style": {
+            "dash": false
+        },
+        "created_by": null,
+        "shape": "circle",
+        "type": "default"
+    }],
+    "edges": [{
+        "_id": "edge-2016-06-21-80cce7b7-030f-45f0-bb04-f8a771faee5f-0002",
+        "title": "test edge 1",
+        "uri": "http://example.com",
+        "description": "edge 1",
+        "from": "node-2016-06-21-80cce7b7-030f-45f0-bb04-f8a771faee5f-0001",
+        "to": "node-2016-06-21-6388a022-27c6-4f4a-8fb3-318b34d5ce9c-0001",
+        "created_by": null
+    }, {
+        "_id": "edge-2016-06-21-80cce7b7-030f-45f0-bb04-f8a771faee5f-0003",
+        "title": "test edge 2",
+        "uri": "",
+        "description": "",
+        "from": "node-2016-06-21-80cce7b7-030f-45f0-bb04-f8a771faee5f-0001",
+        "to": "node-2016-04-07-a9fe3711-8006-4a5d-b96a-0ab1630ee7de-0001",
+        "created_by": null
+    }],
+    "views": [{
+        "_id": "view-9ecf59d9-2452-4af9-b3a0-b4f8714d2a33",
+        "zoom_level": 3.044776119402986,
+        "offset": {
+            "x": 1605.8805970149256,
+            "y": 425.62687488438837
+        },
+        "title": "test view 1",
+        "description": "",
+        "created_by": null,
+        "hidden_nodes": ["node-2016-06-21-80cce7b7-030f-45f0-bb04-f8a771faee5f-0001"]
+    }],
+    "title": "test",
+    "schema_version": "2",
+    "space_id": "111",
+    "created": "2016-03-11 12:15:13.030697+00:00",
+    "updated": "2016-06-21 15:08:17.584479+00:00",
+    "description": "test description",
+    "id": "c0bd5f0b-5559-40e0-92a2-fe2cb6cf8de6"
+}