# HG changeset patch # User ymh # Date 1467234716 -7200 # Node ID 11291230972681ce9e8f80dcb5eb2193783d1621 # Parent 4d67ae41b9b319ce8d8ff499ddbfc6a532b3d5ca ensure that we change the ids of elements when copying/creating a new renkan diff -r 4d67ae41b9b3 -r 112912309726 server/python/django2/renkanmanager/api/views.py --- 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) diff -r 4d67ae41b9b3 -r 112912309726 server/python/django2/renkanmanager/models.py --- 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: diff -r 4d67ae41b9b3 -r 112912309726 server/python/django2/renkanmanager/serializers.py --- 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) diff -r 4d67ae41b9b3 -r 112912309726 server/python/django2/renkanmanager/tests/test_models.py --- /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) diff -r 4d67ae41b9b3 -r 112912309726 server/python/django2/renkanmanager/tests/test_revision_copy.json --- /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" +}