--- 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"
+}