|
| 1 | +/* Copyright 2017 Krzysztof Daniel. |
| 2 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 | +you may not use this file except in compliance with the License. |
| 4 | +You may obtain a copy of the License at |
| 5 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 6 | +Unless required by applicable law or agreed to in writing, software |
| 7 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 8 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 9 | +See the License for the specific language governing permissions and |
| 10 | +limitations under the License.*/ |
| 11 | +/*jshint esversion: 6 */ |
| 12 | + |
| 13 | + |
| 14 | +var mongoose = require('mongoose'); |
| 15 | +var Schema = mongoose.Schema; |
| 16 | +var ObjectId = mongoose.Types.ObjectId; |
| 17 | +var modelLogger = require('./../../log').getLogger('MapSchema'); |
| 18 | +var _ = require('underscore'); |
| 19 | +var q = require('q'); |
| 20 | + |
| 21 | + |
| 22 | +function makeDependencyTo(jsonLink, id, node){ |
| 23 | + if (!node) { |
| 24 | + console.error('Could not establish', jsonLink, id); |
| 25 | + return null; |
| 26 | + } |
| 27 | + // this calls save |
| 28 | + return node.makeDependencyTo(id); |
| 29 | +} |
| 30 | + |
| 31 | +module.exports.mapImport = function(Node, workspace, incomingMapJSON) { |
| 32 | + if (!workspace) { |
| 33 | + return null; |
| 34 | + } |
| 35 | + return workspace |
| 36 | + /* create an empty map with just the title */ |
| 37 | + .createAMap({ |
| 38 | + name: incomingMapJSON.title |
| 39 | + }) |
| 40 | + /* create all the imported nodes */ |
| 41 | + .then(function(emptyMap) { |
| 42 | + var promises = []; |
| 43 | + |
| 44 | + for (let i = 0; i < incomingMapJSON.elements.length; i++) { |
| 45 | + let currentNode = incomingMapJSON.elements[i]; |
| 46 | + promises.push(new Node({ |
| 47 | + name: currentNode.name, |
| 48 | + x: 1 - currentNode.maturity, |
| 49 | + y: 1 - currentNode.visibility, |
| 50 | + type: "INTERNAL", |
| 51 | + workspace: emptyMap.workspace, |
| 52 | + parentMap: emptyMap._id, |
| 53 | + description: "", |
| 54 | + inertia: 0, |
| 55 | + responsiblePerson: "", |
| 56 | + constraint: 0, |
| 57 | + foreignKey: currentNode.id // this needs to be stored for export and external diffs |
| 58 | + }).save()); |
| 59 | + } |
| 60 | + |
| 61 | + /* once nodes are created, push them into nodes array */ |
| 62 | + return q.allSettled(promises).then(function(results) { |
| 63 | + for (let i = 0; i < results.length; i++) { |
| 64 | + emptyMap.nodes.push(results[i].value); |
| 65 | + } |
| 66 | + return emptyMap.save(); |
| 67 | + }); |
| 68 | + }) |
| 69 | + .then(function(mapWithNodes) { |
| 70 | + // at this point we have a map with nodes and foreign keys |
| 71 | + // we need to translate json connections (based on foreign keys) |
| 72 | + // to use real _id we have in db |
| 73 | + |
| 74 | + |
| 75 | + // iteration one, build a lookup table connecting foreignKey with _ids |
| 76 | + // created by db during save in previous chapter |
| 77 | + let foreignKeyMap = {}; |
| 78 | + for (let i = 0; i < mapWithNodes.nodes.length; i++) { |
| 79 | + let foreignKey = mapWithNodes.nodes[i].foreignKey; |
| 80 | + // the node may or not be expanded. Try to use _id (expanded), |
| 81 | + // and if there is none, use the object (hopefully _id). |
| 82 | + foreignKeyMap[foreignKey] = mapWithNodes.nodes[i]._id || mapWithNodes.nodes[i]; |
| 83 | + } |
| 84 | + |
| 85 | + // iterate over JSON links and establish appropriate connections |
| 86 | + // use foreignKey to locate real dependency _id |
| 87 | + let promises = []; |
| 88 | + for (let i = 0; i < incomingMapJSON.links.length; i++) { |
| 89 | + promises.push( |
| 90 | + Node |
| 91 | + .findOne(foreignKeyMap[incomingMapJSON.links[i].start]) |
| 92 | + .exec() |
| 93 | + .then( |
| 94 | + makeDependencyTo.bind( |
| 95 | + this, |
| 96 | + incomingMapJSON.links[i], //for debugging only |
| 97 | + foreignKeyMap[incomingMapJSON.links[i].end]) //the dep to be made |
| 98 | + ) |
| 99 | + ); |
| 100 | + } |
| 101 | + // and once all connections are saved, return the fully imported map |
| 102 | + return q.allSettled(promises).then(function(r) { |
| 103 | + return mapWithNodes.defaultPopulate(); |
| 104 | + }); |
| 105 | + }); |
| 106 | +}; |
| 107 | + |
| 108 | +module.exports.mapExport = function(map) { |
| 109 | + let newMap = { |
| 110 | + title: '', |
| 111 | + elements: [], |
| 112 | + links: [] |
| 113 | + }; |
| 114 | + newMap.title = map.name; |
| 115 | + |
| 116 | + let foreignKeyMap = {}; |
| 117 | + for (let i = 0; i < map.nodes.length; i++) { |
| 118 | + foreignKeyMap['' + map.nodes[i]._id] = map.nodes[i].foreignKey; |
| 119 | + } |
| 120 | + |
| 121 | + for (let i = 0; i < map.nodes.length; i++) { |
| 122 | + let node = map.nodes[i]; |
| 123 | + //translate nodes |
| 124 | + newMap.elements.push({ |
| 125 | + id: '' + (node.foreignKey || node._id), |
| 126 | + name: node.name, |
| 127 | + visibility: 1 - node.y, //atlas uses screen based positioning |
| 128 | + maturity: 1 - node.x |
| 129 | + }); |
| 130 | + |
| 131 | + //translate links |
| 132 | + for (let j = 0; j < node.outboundDependencies.length; j++) { |
| 133 | + let targetId = node.outboundDependencies[j]; |
| 134 | + newMap.links.push({ |
| 135 | + start: '' + (foreignKeyMap['' + node._id] || node._id), |
| 136 | + end: '' + (foreignKeyMap[targetId] || targetId) |
| 137 | + }); |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + // sort nodes to avoid unnecessary diffs |
| 142 | + newMap.elements.sort(function(a, b) { |
| 143 | + let aName = a.id; |
| 144 | + let bName = b.id; |
| 145 | + if (aName < bName) { |
| 146 | + return -1; |
| 147 | + } |
| 148 | + if (aName > bName) { |
| 149 | + return 1; |
| 150 | + } |
| 151 | + return 0; |
| 152 | + }); |
| 153 | + |
| 154 | + newMap.links.sort(function(a, b) { |
| 155 | + if (a.start < b.start) { |
| 156 | + return -1; |
| 157 | + } |
| 158 | + if (a.start > b.start) { |
| 159 | + return 1; |
| 160 | + } |
| 161 | + if (a.end < b.end) { |
| 162 | + return -1; |
| 163 | + } |
| 164 | + if (a.end > b.end) { |
| 165 | + return 1; |
| 166 | + } |
| 167 | + return 0; |
| 168 | + }); |
| 169 | + |
| 170 | + return newMap; |
| 171 | +}; |
0 commit comments