From c2465ab9595bcefd73ecd19b6628180580e01921 Mon Sep 17 00:00:00 2001 From: Robert Pergl Date: Tue, 25 Dec 2018 17:57:33 +0100 Subject: [PATCH] refactoring necessary fixes: TODO.md --- TODO.md | 6 +- app/db/general.js | 49 +-- app/db/ufoa.js | 84 ++--- app/view/ufoa/dialogs/entityDialog.js | 24 +- data/ufoa-graphics.json | 8 - ...backup.json => ufoa-graphics.json.backup2} | 8 - data/ufoa.json | 23 +- data/ufob-graphics.json | 304 +++++++++--------- data/ufob.json | 24 ++ package-lock.json | 121 +++++-- package.json | 1 + server/app.js | 216 +++++++------ server/db/general.js | 87 +++-- server/db/ufoa.js | 212 ++++++------ server/db/ufob.js | 140 ++++---- server/logging.js | 8 + shared/ajax.js | 7 + shared/model/ufoa.js | 24 +- shared/urls.js | 16 +- 19 files changed, 777 insertions(+), 585 deletions(-) rename data/{ufoa-graphics.backup.json => ufoa-graphics.json.backup2} (98%) create mode 100644 server/logging.js create mode 100644 shared/ajax.js diff --git a/TODO.md b/TODO.md index 97c2585..19fd2af 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,5 @@ -- refactor update a delete v UFO-A na postData -- zkusit abstrahovat lock na withLock +- opravit mazani entit na serveru +- mazani grafiky entit +- UFO-B mazani elementu: pridat mazani grafiky + - refactor to https://www.primefaces.org/primereact \ No newline at end of file diff --git a/app/db/general.js b/app/db/general.js index f5ab312..1b87558 100644 --- a/app/db/general.js +++ b/app/db/general.js @@ -1,31 +1,40 @@ // @flow -export const requestFailedMsg = "Request to server failed"; +export function ajax(url: string, method: "POST" | "GET", data: any): Promise { + const params = { + method, + body: data ? JSON.stringify(data) : null, + headers: { + "Content-Type": "application/json" + }, + credentials: "same-origin" + }; -export function getData(url: string): Promise { return new Promise((resolve, reject) => { - $.get(url, (data: any, status: String) => { - if (status !== "success") { - console.error(status); - reject(status); - } else { - resolve(data); - } - }).fail(() => reject(requestFailedMsg)); + fetch(url, params).then( + response => { + if (response.status !== 200) { + reject(response.statusText); + } else { + if (method === "GET") { + resolve(response.json()); + } else { + resolve(); + } + } + }, + error => reject(error.message) + ); }); } +export function getData(url: string): Promise { + return ajax(url, "GET", null); +} + export function postData(url: string, data: any): Promise { - return new Promise((resolve, reject) => { - $.post(url, data, (response) => { - if (response.error) { - console.error(response.error); - reject(response.error); - } else { - resolve(response.result); - } - }).fail(() => reject(requestFailedMsg)); - }); + return ajax(url, "POST", data); } + diff --git a/app/db/ufoa.js b/app/db/ufoa.js index 454e5b3..0ad6b91 100644 --- a/app/db/ufoa.js +++ b/app/db/ufoa.js @@ -1,11 +1,11 @@ // @flow -import type { Id, Label } from '../metamodel/general'; -import type { UfoaEntity, Generalisation, GSet, Association, AssocType, AssocMeta, Connection, UfoaModel } from '../metamodel/ufoa'; +import type { Id } from '../metamodel/general'; +import type { UfoaEntity, Generalisation, GSet, Association, UfoaModel } from '../metamodel/ufoa'; import * as ufoaMeta from '../metamodel/ufoa'; import * as urls from "../urls"; import * as ufoaModel from '../model/ufoa'; -import { getData, postData, requestFailedMsg } from './general'; +import { getData, postData } from './general'; var model: UfoaModel = ufoaMeta.emptyModel; @@ -13,10 +13,12 @@ var model: UfoaModel = ufoaMeta.emptyModel; export function loadModel(): Promise { return new Promise((resolve, reject) => { - getData(urls.baseURL + urls.ufoaGetModel).then(data => { - model = data; - resolve(data); - }, (error) => reject(error)); + getData(urls.baseURL + urls.ufoaGetModel).then( + data => { + model = data; + resolve(data); + }, + error => reject(error)); }); } @@ -48,27 +50,21 @@ export function updateEntity(updatedEntity: UfoaEntity): Promise { if (validity.errors) { reject("Entity update failed: " + validity.errors); } else { - $.post(urls.baseURL + urls.ufoaEntityUpdate, { entity: JSON.stringify(updatedEntity) }, (response) => { - if (response.error) { - reject(response.error); - } else { - resolve(response.result); - } - }).fail(() => reject(requestFailedMsg)); + postData(urls.baseURL + urls.ufoaEntityUpdate, { entity: JSON.stringify(updatedEntity) }).then( + () => resolve(), + error => reject(error) + ); } }); } export function deleteEntity(e_id: Id): Promise { return new Promise((resolve, reject) => { - ufoaModel.deleteEntity(model, e_id); - $.post(urls.baseURL + urls.ufoaEntityDelete, { e_id }, (response) => { - if (response.error) { - reject(response.error); - } else { - resolve(response.result); - } - }).fail(() => reject(requestFailedMsg)); + model = ufoaModel.deleteEntity(model, e_id); + postData(urls.baseURL + urls.ufoaEntityDelete, { e_id }).then( + () => resolve(), + error => reject(error) + ); }); } @@ -96,13 +92,10 @@ export function updateGeneralisation(updatedGeneralisation: Generalisation): Pro if (validity.errors) { console.error("Generalisation update failed: " + validity.errors); } else { - $.post(urls.baseURL + urls.generalisationUpdate, { generalisation: JSON.stringify(updatedGeneralisation) }, (response) => { - if (response.error) { - reject(response.error); - } else { - resolve(response.result); - } - }).fail(() => reject(requestFailedMsg)); + postData(urls.baseURL + urls.generalisationUpdate, { generalisation: JSON.stringify(updatedGeneralisation) }).then( + () => resolve(), + error => reject(error) + ); } }); } @@ -110,13 +103,10 @@ export function updateGeneralisation(updatedGeneralisation: Generalisation): Pro export function deleteGeneralisation(g_id: Id): Promise { return new Promise((resolve, reject) => { ufoaModel.deleteGeneralisation(model, g_id); - $.post(urls.baseURL + urls.ufoaGeneralisationDelete, { g_id }, (response) => { - if (response.error) { - reject(response.error); - } else { - resolve(response.result); - } - }).fail(() => reject(requestFailedMsg)); + postData(urls.baseURL + urls.ufoaGeneralisationDelete, { g_id }).then( + () => resolve(), + error => reject(error) + ); }); } @@ -144,13 +134,10 @@ export function updateAssociation(updatedAssociation: Association): Promise if (validity.errors) { console.error("Association update failed: " + validity.errors); } else { - $.post(urls.baseURL + urls.associationUpdate, { association: JSON.stringify(updatedAssociation) }, (response) => { - if (response.error) { - reject(response.error); - } else { - resolve(response.result); - } - }).fail(() => reject(requestFailedMsg)); + postData(urls.baseURL + urls.associationUpdate, { association: JSON.stringify(updatedAssociation) }).then( + () => resolve(), + error => reject(error) + ); } }); } @@ -158,13 +145,10 @@ export function updateAssociation(updatedAssociation: Association): Promise export function deleteAssociation(a_id: Id): Promise { return new Promise((resolve, reject) => { ufoaModel.deleteAssociation(model, a_id); - $.post(urls.baseURL + urls.ufoaAssociationDelete, { a_id }, (response) => { - if (response.error) { - reject(response.error); - } else { - resolve(response.result); - } - }).fail(() => reject(requestFailedMsg)); + postData(urls.baseURL + urls.ufoaAssociationDelete, { a_id }).then( + () => resolve(), + error => reject(error) + ); }); } diff --git a/app/view/ufoa/dialogs/entityDialog.js b/app/view/ufoa/dialogs/entityDialog.js index 68c203f..7fcc919 100644 --- a/app/view/ufoa/dialogs/entityDialog.js +++ b/app/view/ufoa/dialogs/entityDialog.js @@ -23,11 +23,13 @@ type State = { }; function commitEntity(nodes: any, e: UfoaEntity) { - ufoaDB.updateEntity(e).then((response) => { - nodes.update({ id: e.e_id, label: ufoaMeta.entityStr(e) }); - panels.hideDialog(); - panels.displayInfo("Entity saved."); - }, (error) => panels.displayError("Entity save failed: " + error)); + ufoaDB.updateEntity(e).then( + () => { + nodes.update({ id: e.e_id, label: ufoaMeta.entityStr(e) }); + panels.hideDialog(); + panels.displayInfo("Entity saved."); + }, + error => panels.displayError("Entity save failed: " + error)); } class UfoaNodeForm extends React.Component { @@ -66,11 +68,13 @@ class UfoaNodeForm extends React.Component { delete = (event) => { let nodes: any = this.props.ufoaVisModel.nodes; let e_id = this.props.ufoaEntity.e_id; - ufoaDB.deleteEntity(e_id).then((response) => { - nodes.remove({ id: e_id }); - panels.hideDialog(); - panels.displayInfo("Entity deleted."); - }, (error) => panels.displayError("Entity delete failed: " + error)); + ufoaDB.deleteEntity(e_id).then( + () => { + nodes.remove({ id: e_id }); + panels.hideDialog(); + panels.displayInfo("Entity deleted."); + }, + error => panels.displayError("Entity delete failed: " + error)); } renderEntityType() { diff --git a/data/ufoa-graphics.json b/data/ufoa-graphics.json index c1959d4..1bb03a8 100644 --- a/data/ufoa-graphics.json +++ b/data/ufoa-graphics.json @@ -482,13 +482,5 @@ "e120": { "x": -1973, "y": -1071 - }, - "e121": { - "x": -1897, - "y": -1318 - }, - "e122": { - "x": -267, - "y": -9082 } } \ No newline at end of file diff --git a/data/ufoa-graphics.backup.json b/data/ufoa-graphics.json.backup2 similarity index 98% rename from data/ufoa-graphics.backup.json rename to data/ufoa-graphics.json.backup2 index c1959d4..1bb03a8 100644 --- a/data/ufoa-graphics.backup.json +++ b/data/ufoa-graphics.json.backup2 @@ -482,13 +482,5 @@ "e120": { "x": -1973, "y": -1071 - }, - "e121": { - "x": -1897, - "y": -1318 - }, - "e122": { - "x": -267, - "y": -9082 } } \ No newline at end of file diff --git a/data/ufoa.json b/data/ufoa.json index 2eca9ef..eedb757 100644 --- a/data/ufoa.json +++ b/data/ufoa.json @@ -607,8 +607,8 @@ }, { "e_id": "e121", - "e_type": "mode", - "e_name": "Follow-up Results" + "e_type": "kind", + "e_name": "xxx" } ], "generalisations": [ @@ -2888,25 +2888,6 @@ } } }, - { - "a_id": "a80", - "a_type": "characterization", - "a_meta": "", - "a_label": "", - "a_connection1": { - "e_id": "e120", - "mult": { - "lower": 1, - "upper": 1 - } - }, - "a_connection2": { - "e_id": "e121", - "mult": { - "lower": 1 - } - } - }, { "a_id": "a81", "a_type": "mediation", diff --git a/data/ufob-graphics.json b/data/ufob-graphics.json index e80c77a..518e794 100644 --- a/data/ufob-graphics.json +++ b/data/ufob-graphics.json @@ -1,302 +1,306 @@ { "s1": { - "x": 928, - "y": -2962 + "x": -626, + "y": -3026 }, "s2": { - "x": 69, - "y": -2721 + "x": 443, + "y": -3072 }, "s3": { - "x": 907, - "y": -2672 + "x": -726, + "y": -2414 }, "s4": { - "x": 908, - "y": -2376 + "x": -79, + "y": 244 }, "s5": { - "x": 43, - "y": -2414 + "x": 548, + "y": -2437 }, "s6": { - "x": -117, - "y": -2127 + "x": -47, + "y": -2077 }, "s7": { - "x": -146, - "y": -1198 + "x": -16, + "y": -1164 }, "s8": { - "x": 463, - "y": -1829 + "x": 806, + "y": -1812 }, "s9": { - "x": -425, - "y": -1620 + "x": -385, + "y": -1520 }, "s10": { - "x": 134, - "y": -1573 + "x": 302, + "y": -1564 }, "s11": { - "x": 367, - "y": -1390 + "x": 575, + "y": -1307 }, "s12": { - "x": -169, - "y": -812 + "x": -241, + "y": -948 }, "s13": { - "x": -381, - "y": -450 + "x": -96, + "y": -466 }, "s14": { - "x": 62, - "y": -408 + "x": 213, + "y": -342 }, "s15": { - "x": -175, - "y": -71 + "x": -627, + "y": -316 }, "s16": { - "x": -257, - "y": 289 + "x": -238, + "y": -39 }, "s17": { - "x": -262, - "y": 688 + "x": -502, + "y": 575 }, "s18": { - "x": -248, - "y": 973 + "x": -578, + "y": 979 }, "s19": { - "x": 1165, - "y": 18 + "x": 276, + "y": 189 }, "s20": { - "x": 601, - "y": 800 + "x": 29, + "y": 776 }, "s21": { - "x": -603, - "y": 1469 + "x": -2021, + "y": 1050 }, "s22": { - "x": -1934, - "y": 1934 + "x": -1872, + "y": 2121 }, "s23": { - "x": -1443, - "y": 2435 + "x": -1593, + "y": 2562 }, "s24": { - "x": -1453, - "y": 2899 + "x": -1567, + "y": 2890 }, "s25": { - "x": -1564, - "y": 3311 + "x": -655, + "y": 2238 }, "s26": { - "x": -1584, - "y": 3782 + "x": -239, + "y": 3012 }, "s27": { - "x": -2079, - "y": 2500 + "x": -1901, + "y": 2585 }, "s28": { - "x": -1995, - "y": 2981 + "x": -1893, + "y": 2886 }, "s29": { - "x": -2085, - "y": 3442 + "x": -1910, + "y": 3239 }, "s30": { - "x": 1256, - "y": 588 + "x": 811, + "y": 686 }, "s31": { - "x": 1164, - "y": 1040 + "x": 864, + "y": 1142 }, "s32": { - "x": 1188, - "y": 1520 + "x": 818, + "y": 1553 }, "s33": { - "x": 1199, - "y": 1976 + "x": 852, + "y": 1994 }, "s34": { - "x": 1213, - "y": 2402 + "x": 849, + "y": 2441 }, "s35": { - "x": 1133, - "y": 2904 + "x": 842, + "y": 2899 }, "s36": { - "x": 1170, - "y": 3526 + "x": 843, + "y": 3473 }, "s37": { - "x": -1769, - "y": 2832 + "x": -1112, + "y": 2660 }, "e1": { - "x": 915, - "y": -2820 + "x": -601, + "y": -2701 }, "e2": { - "x": 55, - "y": -2558 + "x": 485, + "y": -2746 }, "e3": { - "x": 924, - "y": -2524 + "x": -740, + "y": -2065 }, "e4": { - "x": 56, - "y": -2267 + "x": 205, + "y": -2318 }, "e5": { - "x": 120, - "y": 1885 + "x": -158, + "y": 1302 + }, + "e6": { + "x": 44, + "y": 478 }, "e7": { - "x": 1093, - "y": 325 + "x": 821, + "y": 412 }, "e8": { - "x": -137, - "y": -1411 + "x": -23, + "y": -1462 }, "e9": { - "x": -405, - "y": -1947 + "x": -361, + "y": -1881 }, "e10": { - "x": 140, - "y": -1890 + "x": 314, + "y": -1905 }, "e11": { - "x": 471, - "y": -2081 + "x": 796, + "y": -2155 }, "e12": { - "x": -126, - "y": -1012 + "x": 376, + "y": -1002 }, "e13": { - "x": 423, - "y": -1619 + "x": 883, + "y": -1475 }, "e14": { - "x": 55, - "y": -635 + "x": 463, + "y": -637 }, "e15": { - "x": -362, - "y": -640 + "x": 44, + "y": -751 }, "e16": { - "x": -149, - "y": -237 + "x": -433, + "y": -584 }, "e17": { - "x": -250, - "y": 78 + "x": -442, + "y": -111 }, "e18": { - "x": -256, - "y": 444 + "x": -472, + "y": 350 }, "e19": { - "x": -241, - "y": 832 + "x": -363, + "y": 795 }, "e20": { - "x": -434, - "y": 1198 + "x": -441, + "y": 1214 }, "e21": { - "x": 1217, - "y": -2388 + "x": 274, + "y": 16 }, "e22": { - "x": 600, - "y": 483 + "x": 214, + "y": 902 }, "e23": { - "x": -1025, - "y": 1685 + "x": 456, + "y": 1003 }, "e24": { - "x": -639, - "y": 1822 + "x": -2022, + "y": 1492 }, "e25": { - "x": -1383, - "y": 1593 + "x": -1398, + "y": 636 }, "e26": { - "x": -2030, - "y": 2229 + "x": -1905, + "y": 2388 }, "e27": { - "x": -1554, - "y": 2158 + "x": -1604, + "y": 2382 }, "e28": { - "x": -1358, - "y": 2681 + "x": -1578, + "y": 2736 }, "e29": { - "x": -1458, - "y": 3120 + "x": -1246, + "y": 1763 }, "e30": { - "x": -1758, - "y": 2535 + "x": -1708, + "y": 2669 }, "e31": { - "x": -1650, - "y": 3532 + "x": -715, + "y": 2737 }, "e32": { - "x": -2235, - "y": 2747 + "x": -1884, + "y": 2737 }, "e33": { - "x": -2224, - "y": 3161 + "x": -1898, + "y": 3051 }, "e34": { - "x": 1032, - "y": 802 + "x": 910, + "y": 909 }, "e35": { - "x": 1208, - "y": 1281 + "x": 739, + "y": 1340 }, "e36": { - "x": 1076, - "y": 1742 + "x": 829, + "y": 1774 }, "e37": { - "x": 1027, - "y": 2194 + "x": 824, + "y": 2219 }, "e38": { - "x": 1271, - "y": 2662 + "x": 866, + "y": 2658 }, "e39": { - "x": 1170, - "y": 3192 + "x": 840, + "y": 3141 } } \ No newline at end of file diff --git a/data/ufob.json b/data/ufob.json index 486502c..406bb0a 100644 --- a/data/ufob.json +++ b/data/ufob.json @@ -720,6 +720,30 @@ "s_id": "s37", "s_name": "Donor Follow-Up", "s_dispositions": [] + }, + { + "s_id": "s38", + "s_name": "New Situation2", + "s_dispositions": [ + { + "d_text": "", + "d_events_ids": [ + "e17" + ] + } + ] + }, + { + "s_id": "s39", + "s_name": "New Situation3", + "s_dispositions": [ + { + "d_text": "", + "d_events_ids": [ + "e18" + ] + } + ] } ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 93ca87b..e554cba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1092,10 +1092,12 @@ "dev": true }, "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } }, "anymatch": { "version": "2.0.0", @@ -1490,6 +1492,33 @@ "chalk": "^1.1.3", "esutils": "^2.0.2", "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } } }, "babel-helper-function-name": { @@ -2059,16 +2088,13 @@ } }, "chalk": { - "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "check-dependencies": { @@ -2085,11 +2111,36 @@ "semver": "^5.3.0" }, "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, "minimist": { "version": "1.2.0", "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true } } }, @@ -2235,7 +2286,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -2243,8 +2293,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "colorette": { "version": "1.0.4", @@ -3163,6 +3212,33 @@ "requires": { "chalk": "^1.1.3", "flow-bin": ">=0.35.0 <1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } } }, "for-in": { @@ -3877,8 +3953,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.0", @@ -6372,10 +6447,12 @@ } }, "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } }, "tag-shell": { "version": "0.1.0", diff --git a/package.json b/package.json index 8a6e3f4..13a87c2 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "dependencies": { "ajv": "^6.5.4", "bootstrap3": "^3.3.5", + "chalk": "^2.4.1", "cookie-parser": "^1.4.3", "cors": "^2.8.4", "debug": "^4.1.0", diff --git a/server/app.js b/server/app.js index a0338d8..8c46c1e 100644 --- a/server/app.js +++ b/server/app.js @@ -1,15 +1,30 @@ //@flow -var express = require('express'); -var cors = require('cors'); -var path = require('path'); -var cookieParser = require('cookie-parser'); -var logger = require('morgan'); -var ufoaMeta = require('./metamodel/ufoa'); -var ufobMeta = require('./metamodel/ufob'); -var ufoaDB = require('./db/ufoa'); -var ufobDB = require('./db/ufob'); -var urls = require('./urls'); +const express = require('express'); +const cors = require('cors'); +const path = require('path'); +const cookieParser = require('cookie-parser'); +const logger = require('morgan'); +const ufoaMeta = require('./metamodel/ufoa'); +const ufobMeta = require('./metamodel/ufob'); +const ufoaDB = require('./db/ufoa'); +const ufobDB = require('./db/ufob'); +const urls = require('./urls'); + +function clientErrRes(res: any, msg: string): void { + res.status(400); + res.send(msg); +} + +function serverErrRes(res: any, msg: string): void { + res.status(500); + res.send(msg); +} + +function okRes(res: any, result: any): void { + res.status(200); + res.json(result); +} var app = express(); @@ -23,44 +38,16 @@ app.use(express.static(path.join(__dirname, '../public'))); // Home app.get('/', (req, res: any) => { - res.render('index.html'); + res.status(200).render('index.html'); }); // UFO-A app.get(urls.ufoaGetModel, (req, res: any) => { - ufoaDB.getModel().then(model => { - res.json(model); - }, (error) => { - res.json( {error: `Server error in loading UFO-A model: ${error}` }); - }); -}); - -app.get(urls.ufoaGetGraphics, (req, res: any) => { - ufoaDB.getGraphics().then(graphics => { - res.json(graphics); - }, (error) => { - res.json( {error: `Server error in loading UFO-A model layout: ${error}` }); - }); -}); - -app.post(urls.ufoaGraphicsSave, (req, res: any) => { - try { - const graphics = JSON.parse(req.body.graphics); - ufoaDB.saveGraphics(graphics, (result) => { - res.json(result); - }); - } catch (SyntaxError) { - res.json({ error: "Unable to parse `graphics` object" }); - } -}); - -app.post(urls.ufoaGraphicsDelete, (req, res: any) => { - ufoaDB.graphicsDelete().then((result) => { - res.json(result); - }, (error) => { - res.json( {error: `Server error in deleting UFO-A model layout: ${error}` }); - }); + ufoaDB.getModel().then( + model => okRes(res, model), + error => serverErrRes(res, `Error in loading UFO-A model: ${error}`) + ); }); // Entities @@ -70,55 +57,58 @@ app.post(urls.ufoaEntityUpdate, (req, res: any) => { const entity = JSON.parse(req.body.entity); const validity = ufoaMeta.validateEntity(entity); if (validity.errors) { - res.json(validity); + serverErrRes(res, "Error in entity update (validity violation)"); } else { - ufoaDB.updateEntity(entity, (result) => { - res.json(result); - }); + ufoaDB.updateEntity(entity).then( + result => okRes(res, result), + error => serverErrRes(res, `Error in updating entity: ${error}`) + ); } } catch (SyntaxError) { - res.json({error: "Unable to parse `entity` object"}); + clientErrRes(res, "Unable to parse `entity` object"); } }); app.post(urls.ufoaEntityDelete, (req, res: any) => { let e_id = req.body.e_id; if (!e_id) { - res.json({error: "Missing `e_id`"}); + clientErrRes(res, "Missing `e_id`"); } else { - ufoaDB.deleteEntity(e_id, (result) => { - res.json(result); - }); + ufoaDB.deleteEntity(e_id).then( + result => okRes(res, result), + error => serverErrRes(res, `Error in deleting entity: ${error}`) + ); } }); // Generalisations app.post(urls.generalisationUpdate, (req, res: any) => { - let generalisation = {}; try { const generalisation = JSON.parse(req.body.generalisation); const validity = ufoaMeta.validateGeneralisation(generalisation); if (validity.errors) { - res.json(validity); + serverErrRes(res, "Validity error on generalisation update"); } else { - ufoaDB.updateGeneralisation(generalisation, (result) => { - res.json(result); - }); + ufoaDB.updateGeneralisation(generalisation).then( + result => okRes(res, result), + error => serverErrRes(res, `Error in updating generalisation: ${error}`) + ); } } catch (SyntaxError) { - res.json({error: "Unable to parse `generalisation` object"}); + clientErrRes(res, "Unable to parse `generalisation` object"); } }); app.post(urls.ufoaGeneralisationDelete, (req, res: any) => { const g_id = req.body.g_id; if (!g_id) { - res.json({error: "Missing `g_id`"}); + clientErrRes(res, "Missing `g_id`"); } else { - ufoaDB.deleteGeneralisation(g_id, (result) => { - res.json(result); - }); + ufoaDB.deleteGeneralisation(g_id).then( + result => okRes(res, result), + error => serverErrRes(res, `Error in deleting generalisation: ${error}`) + ); } }); @@ -129,59 +119,69 @@ app.post(urls.associationUpdate, (req, res: any) => { const assoc = JSON.parse(req.body.association); const validity = ufoaMeta.validateAssociation(assoc); if (validity.errors) { - res.json(validity); + serverErrRes(res, "Validity error on association update"); } else { - ufoaDB.updateAssociation(assoc, (result) => { - res.json(result); - }); + ufoaDB.updateAssociation(assoc).then( + result => okRes(res, result), + error => serverErrRes(res, `Error in updating association: ${error}`) + ); } } catch (SyntaxError) { - res.json({error: "Unable to parse `association` object"}); + clientErrRes(res, "Unable to parse `association` object"); } }); app.post(urls.ufoaAssociationDelete, (req, res: any) => { const a_id = req.body.a_id; if (!a_id) { - res.json({error: "Missing `a_id`"}); + clientErrRes(res, "Missing `a_id`"); } else { - ufoaDB.deleteAssociation(a_id, (result) => { - res.json(result); - }); + ufoaDB.deleteAssociation(a_id).then( + result => okRes(res, result), + error => serverErrRes(res, `Error in deleting association: ${error}`) + ); } }); -// UFO-B - -// Model - -app.get(urls.ufobGetModel, (req, res: any) => { - ufobDB.getModel().then(model => { - res.json(model); - }, (error) => { - res.json( {error: `Server error in loading UFO-B model: ${error}` }); - }); -}); +// Graphics -app.get(urls.ufobGetGraphics, (req, res: any) => { - ufobDB.getGraphics().then(graphics => { - res.json(graphics); - }, (error) => { - res.json( {error: `Server error in loading UFO-B model layout: ${error}` }); - }); +app.get(urls.ufoaGetGraphics, (req, res: any) => { + ufoaDB.getGraphics().then( + graphics => okRes(res, graphics), + error => serverErrRes(res, `Error in loading UFO-A model layout: ${error}`) + ); }); -app.post(urls.ufobGraphicsSave, (req, res: any) => { +app.post(urls.ufoaGraphicsSave, (req, res: any) => { try { const graphics = JSON.parse(req.body.graphics); - ufoaDB.saveGraphics(graphics, (result) => { - res.json(result); - }); + ufoaDB.saveGraphics(graphics).then( + result => okRes(res, result), + error => serverErrRes(res, error) + ); } catch (SyntaxError) { - res.json({ error: "Unable to parse `graphics` object" }); + clientErrRes(res, "Unable to parse `graphics` object"); } }); +app.post(urls.ufoaGraphicsDelete, (req, res: any) => { + ufoaDB.graphicsDelete().then( + result => okRes(res, result), + error => serverErrRes(res, `Error in deleting UFO-A model layout: ${error}`) + ); +}); + +// UFO-B + +// Model + +app.get(urls.ufobGetModel, (req, res: any) => { + ufobDB.getModel().then( + model => okRes(res, model), + error => serverErrRes(res, `Error in loading UFO-B model: ${error}`) + ); +}); + // Event app.post(urls.ufobEventUpdate, (req, res: any) => { @@ -189,14 +189,15 @@ app.post(urls.ufobEventUpdate, (req, res: any) => { const event = JSON.parse(req.body.event); const validity = ufobMeta.validateEvent(event); if (validity.errors) { - res.json(validity); + serverErrRes(res, "Validity error on Event update"); } else { - ufobDB.updateEvent(event, (result) => { - res.json(result); - }); + ufobDB.updateEvent(event).then( + result => okRes(res, result), + error => serverErrRes(res, `Error in updating event: ${error}`) + ); } } catch (SyntaxError) { - res.json({error: "Unable to parse `event` object"}); + clientErrRes(res, "Unable to parse `event` object"); } }); @@ -240,6 +241,25 @@ app.post(urls.ufobSituationDelete, (req, res: any) => { } }); +// Graphics + +app.get(urls.ufobGetGraphics, (req, res: any) => { + ufobDB.getGraphics().then(graphics => { + res.json(graphics); + }, error => res.json( {error: `Server error in loading UFO-B model layout: ${error}` })); +}); + +app.post(urls.ufobGraphicsSave, (req, res: any) => { + try { + const graphics = JSON.parse(req.body.graphics); + ufobDB.saveGraphics(graphics, (result) => { + res.json(result); + }); + } catch (SyntaxError) { + res.json({ error: "Unable to parse `graphics` object" }); + } +}); +// module.exports = app; diff --git a/server/db/general.js b/server/db/general.js index f492777..db66bea 100644 --- a/server/db/general.js +++ b/server/db/general.js @@ -1,10 +1,27 @@ //@flow -import * as R from 'ramda'; import * as fs from 'fs'; import { lock } from 'proper-lockfile'; +import type { Id } from '../metamodel/general'; +import { error } from '../logging'; -export type RestResult = { result: string } | { error: string}; +export function fileOpWithLock(fname: string, opP: Promise): Promise { + return new Promise((resolve, reject) => { + lock(fname).then(release => { + opP.then( + () => { + release(); + resolve(); + }, + error => { + release(); + error(fname + ": locking of file failed"); + reject(error); + } + ); + }); + }); +} // Model @@ -16,12 +33,12 @@ export function getModel(fname: string, meta: any): Promise { //const validity = true; //console.warn("Validation disabled"); if (!model) { - console.error("Error reading model " + fname); + error("Error reading model " + fname); reject(); } else if (validity.errors) { - console.error(fname + ": model not valid:"); - console.error(validity.errors); - reject(validity.errors); + error(fname + ": model not valid:"); + error(validity.errors); + reject(); } else { resolve(model); } @@ -32,12 +49,14 @@ export function getGraphics(fname: string): Promise { return new Promise((resolve, reject) => { fs.readFile(fname, (err, data) => { if (err) { + error(`Error reading UFO-A graphics file: ${err.message}`); reject(err.message); } else { try { let graphics = JSON.parse(data); resolve(graphics); } catch (SyntaxError) { + error(fname + ": graphics file corrupted"); reject(fname + ": graphics file corrupted"); } } @@ -45,32 +64,60 @@ export function getGraphics(fname: string): Promise { }); } -export function saveGraphics(fname: string, graphics: any, next: (RestResult) => void) { - lock(fname).then((release) => { - fs.writeFile(fname, JSON.stringify(graphics, null, 2), (err) => { - if (err) { - next({ "error": err.message }); - } else { - next({"result": "ok"}); - } - return release(); +export function saveGraphics(fname: string, graphics: any): Promise { + return new Promise((resolve, reject) => { + lock(fname).then((release) => { + fs.writeFile(fname, JSON.stringify(graphics, null, 2), (err) => { + if (err) { + error(fname + ": error saving graphics: " + err.message); + reject(err.message); + } else { + resolve(); + } + return release(); + }); }); }); } export function graphicsDelete(fname: string): Promise { return new Promise((resolve, reject) => { - fs.writeFile(fname, "{}", (err) => { + fs.writeFile(fname, "{}", err => { if (err) { - reject({ "error": err.message }); + error(fname + ": error deleting graphics: " + err.message); + reject(err.message); } else { - resolve({ "result": "success" }); + resolve(); } }); }); } -export function writeModel(model: any, fname: string) { - fs.writeFileSync(fname, JSON.stringify(model, null, 2), 'utf8'); +export function graphicsElementDelete(fname: string, elId: Id): Promise { + return fileOpWithLock(fname, new Promise((resolve, reject) => { + let model = JSON.parse(fs.readFileSync(fname, 'utf8')); + delete model[elId]; + fs.writeFile(fname, model, err => { + if (err) { + error(fname + ": error deleting element graphics: " + err.message); + reject(err.message); + } else { + resolve(); + } + }); + })); +} + +export function writeModel(model: any, fname: string): Promise { + return new Promise((resolve, reject) => { + fs.writeFile(fname, JSON.stringify(model, null, 2), err => { + if (err) { + error("Error writing model: " + err.message); + reject(err.message); + } else { + resolve(); + } + }); + }); } diff --git a/server/db/ufoa.js b/server/db/ufoa.js index dbd0afd..ebe4119 100644 --- a/server/db/ufoa.js +++ b/server/db/ufoa.js @@ -1,13 +1,11 @@ //@flow -import * as R from 'ramda'; -import * as fs from 'fs'; -import { lock } from 'proper-lockfile'; -import type { RestResult } from './general'; import * as db from './general'; -import type { Id, EntityType, UfoaEntity, Generalisation, UfoaModel } from '../metamodel/ufoa'; +import type { Id } from '../metamodel/general'; +import type { UfoaModel } from '../metamodel/ufoa'; import * as ufoaMeta from '../metamodel/ufoa'; import * as ufoaModel from '../model/ufoa'; +import { error } from '../logging'; const ufoaFname = "../data/ufoa.json"; const ufoaGraphicsFname = "../data/ufoa-graphics.json"; @@ -18,122 +16,138 @@ export function getModel(): Promise { return db.getModel(ufoaFname, ufoaMeta); } -export function getGraphics(): Promise { - return db.getGraphics(ufoaGraphicsFname); -} - -export function graphicsDelete(): Promise { - return db.graphicsDelete(ufoaGraphicsFname); -} - -export function saveGraphics(graphics: any, next: (RestResult) => void): Promise { - return db.saveGraphics(ufoaGraphicsFname, graphics, next); -} - -export function writeModel(model: UfoaModel) { - db.writeModel(model, ufoaFname); +export function writeModel(model: UfoaModel): Promise { + return db.writeModel(model, ufoaFname); } // Entities -export function updateEntity(updatedEntity: any, next: (RestResult) => void) { - lock(ufoaFname).then((release) => { - loadSetSaveEntity(updatedEntity, next); - return release(); - }); +export function updateEntity(updatedEntity: any): Promise { + return db.fileOpWithLock(ufoaFname, new Promise((resolve, reject) => { + getModel().then( + model => { + ufoaModel.updateEntity(model, updatedEntity); + const validity = ufoaMeta.validateModel(model); + if (validity.errors) { + error("Consistency error: updating of entity " + updatedEntity.e_id + " with " + JSON.stringify(updatedEntity) + " would brake the model."); + reject("Validity error"); + } else { + writeModel(model).then( + () => resolve(), + error => reject(error) + ); + } + }, + error => reject(error) + ); + })); } -function loadSetSaveEntity(updatedEntity: any, next: (RestResult) => void) { - getModel().then((model) => { - ufoaModel.updateEntity(model, updatedEntity); - const validity = ufoaMeta.validateModel(model); - if (validity.errors) { - console.error("Consistency error: updating of entity " + updatedEntity.e_id + " with " + JSON.stringify(updatedEntity) + " would brake the model."); - next({"error": "Internal server error on UFOA-A entity updating."}); - } else { - writeModel(model); - next({"result": "ok"}); - } - }, (error) => { next({ "error": error, "e_id": updatedEntity.e_id }); }); -} - -export function deleteEntity(e_id: Id, next: (RestResult) => void) { - lock(ufoaFname).then((release) => { +export function deleteEntity(e_id: Id): Promise { + return db.fileOpWithLock(ufoaFname, new Promise((resolve, reject) => { getModel().then((model) => { ufoaModel.deleteEntity(model, e_id); - writeModel(model); - next({"result": "ok"}); - }); - return release(); - }); + writeModel(model).then( + //() => deleteEntityGraphics(e_id).then( + () => resolve(), + error => reject(error) + //), + //error => { error(error); reject(error); } + ); + }); + })); } // Generalisations -export function updateGeneralisation(updatedGeneralisation: any, next: (RestResult) => void) { - lock(ufoaFname).then((release) => { - loadSetSaveGeneralisation(updatedGeneralisation, next); - return release(); - }); +export function updateGeneralisation(updatedGeneralisation: any): Promise { + return db.fileOpWithLock(ufoaFname, new Promise((resolve, reject) => { + getModel().then( + model => { + ufoaModel.updateGeneralisation(model, updatedGeneralisation); + const validity = ufoaMeta.validateModel(model); + if (!validity) { + error("Consistency error: updating of generalisation " + updatedGeneralisation.g_id + " with " + JSON.stringify(updatedGeneralisation) + " would brake the model."); + reject("Validity error"); + } else { + writeModel(model).then( + () => resolve(), + error => reject(error) + ); + } + }, + error => reject(error) + ); + })); } -function loadSetSaveGeneralisation(updatedGeneralisation: any, next: (RestResult) => void) { - getModel().then((model) => { - ufoaModel.updateGeneralisation(model, updatedGeneralisation); - const validity = ufoaMeta.validateModel(model); - if (!validity) { - console.error("Consistency error: updating of generalisation " + updatedGeneralisation.g_id + " with " + JSON.stringify(updatedGeneralisation) + " would brake the model."); - next({"error": "Internal server error on UFOA-A generalisation updating."}); - } else { - writeModel(model); - next({"result": "ok"}); - } - }, (error) => { next({ "error": error, "g_id": updatedGeneralisation.g_id }); }); -} - -export function deleteGeneralisation(g_id: Id, next: (RestResult) => void) { - lock(ufoaFname).then((release) => { - getModel().then((model) => { - ufoaModel.deleteGeneralisation(model, g_id); - writeModel(model); - next({"result": "ok"}); - }); - return release(); - }); +export function deleteGeneralisation(g_id: Id): Promise { + return db.fileOpWithLock(ufoaFname, new Promise((resolve, reject) => { + getModel().then( + model => { + ufoaModel.deleteGeneralisation(model, g_id); + writeModel(model).then( + () => resolve(), + error => reject(error) + ); + }, + error => reject(error) + ); + })); } // Associations -export function updateAssociation(updatedAssociation: any, next: (RestResult) => void) { - lock(ufoaFname).then((release) => { - loadSetSaveAssociation(updatedAssociation, next); - return release(); - }); +export function updateAssociation(updatedAssociation: any): Promise { + return db.fileOpWithLock(ufoaFname, new Promise((resolve, reject) => { + getModel().then( + model => { + ufoaModel.updateAssociation(model, updatedAssociation); + const validity = ufoaMeta.validateModel(model); + if (validity.errors) { + error("Consistency error: updating of association " + updatedAssociation.a_id + " with " + JSON.stringify(updatedAssociation) + " would brake the model."); + reject("Validity error"); + } else { + writeModel(model).then( + () => resolve(), + error => reject(error) + ); + } + }, + error => reject(error) + ); + })); } -function loadSetSaveAssociation(updatedAssociation: any, next: (RestResult) => void) { - getModel().then((model) => { - ufoaModel.updateAssociation(model, updatedAssociation); - const validity = ufoaMeta.validateModel(model); - if (validity.errors) { - console.error("Consistency error: updating of association " + updatedAssociation.a_id + " with " + JSON.stringify(updatedAssociation) + " would brake the model."); - next({"error": "Internal server error on UFOA-A association updating."}); - } else { - writeModel(model); - next({"result": "ok"}); - } - }, (error) => { next({ "error": error, "a_id": updatedAssociation.a_id }); }); +export function deleteAssociation(a_id: Id): Promise { + return db.fileOpWithLock(ufoaFname, new Promise((resolve, reject) => { + getModel().then( + model => { + ufoaModel.deleteAssociation(model, a_id); + writeModel(model).then( + () => resolve(), + error => reject(error) + ); + }, + error => reject(error) + ); + })); } -export function deleteAssociation(a_id: Id, next: (RestResult) => void) { - lock(ufoaFname).then((release) => { - getModel().then((model) => { - ufoaModel.deleteAssociation(model, a_id); - writeModel(model); - next({"result": "ok"}); - }); - return release(); - }); +// Graphics + +export function getGraphics(): Promise { + return db.getGraphics(ufoaGraphicsFname); } +export function graphicsDelete(): Promise { + return db.graphicsDelete(ufoaGraphicsFname); +} +export function saveGraphics(graphics: any): Promise { + return db.saveGraphics(ufoaGraphicsFname, graphics); +} + +function deleteEntityGraphics(e_id: Id): Promise { + return db.graphicsElementDelete(ufoaGraphicsFname, e_id); +} diff --git a/server/db/ufob.js b/server/db/ufob.js index 3e3e16b..301edb4 100644 --- a/server/db/ufob.js +++ b/server/db/ufob.js @@ -1,13 +1,11 @@ //@flow -import * as R from 'ramda'; -import * as fs from 'fs'; -import { lock } from 'proper-lockfile'; import * as db from './general'; -import type { RestResult } from './general'; -import type { Id, Situation, EventB, UfobModel } from '../metamodel/ufob'; +import type { Id } from '../metamodel/general'; +import type { UfobModel } from '../metamodel/ufob'; import * as ufobMeta from '../metamodel/ufob'; import * as ufobModel from '../model/ufob'; +import { error } from '../logging'; const ufobFname = "../data/ufob.json"; const ufobGraphicsFname = "../data/ufob-graphics.json"; @@ -22,83 +20,99 @@ export function getGraphics(): Promise { return db.getGraphics(ufobGraphicsFname); } -export function saveGraphics(graphics: any, next: (RestResult) => void): Promise { - return db.saveGraphics(ufobGraphicsFname, graphics, next); +export function saveGraphics(graphics: any): Promise { + return db.saveGraphics(ufobGraphicsFname, graphics); } export function graphicsDelete(): Promise { return db.graphicsDelete(ufobGraphicsFname); } -export function writeModel(model: UfobModel) { - db.writeModel(model, ufobFname); +export function writeModel(model: UfobModel): Promise { + return db.writeModel(model, ufobFname); } // Event -export function updateEvent(updatedEvent: any, next: (RestResult) => void) { - lock(ufobFname).then((release) => { - loadSetSaveEvent(updatedEvent, next); - return release(); - }); +export function updateEvent(updatedEvent: any): Promise { + return db.fileOpWithLock(ufobFname, new Promise((resolve, reject) => { + getModel().then( + model => { + ufobModel.updateEvent(model, updatedEvent); + const validity = ufobMeta.validateModel(model); + if (validity.errors) { + error("Consistency error: updating of event " + updatedEvent.ev_id + " with " + JSON.stringify(updatedEvent) + " would brake the model."); + reject("Error on UFOB-B event updating."); + } else { + writeModel(model).then( + () => resolve(), + error => reject(error) + ); + } + }, + error => reject(error) + ); + })); } -function loadSetSaveEvent(updatedEvent: any, next: (RestResult) => void) { - getModel().then((model) => { - ufobModel.updateEvent(model, updatedEvent); - const validity = ufobMeta.validateModel(model); - if (validity.errors) { - console.error("Consistency error: updating of event " + updatedEvent.ev_id + " with " + JSON.stringify(updatedEvent) + " would brake the model."); - next({"error": "Internal server error on UFOB-B event updating."}); - } else { - writeModel(model); - next({"result": "ok"}); - } - }, (error) => { next({ "error": error, "ev_id": updatedEvent.ev_id }); }); -} - -export function deleteEvent(ev_id: Id, next: (RestResult) => void) { - lock(ufobFname).then((release) => { - getModel().then((model) => { - ufobModel.deleteEvent(model, ev_id); - writeModel(model); - next({"result": "ok"}); - }); - return release(); - }); +export function deleteEvent(ev_id: Id): Promise { + return db.fileOpWithLock(ufobFname, new Promise((resolve, reject) => { + getModel().then( + model => { + ufobModel.deleteEvent(model, ev_id); + writeModel(model).then( + () => deleteElementGraphics(ev_id).then( + () => resolve(), + error => reject(error) + ), + error => reject(error) + ); + }); + })); } // Situation -export function updateSituation(updatedSituation: any, next: (RestResult) => void) { - lock(ufobFname).then((release) => { - loadSetSaveSituation(updatedSituation, next); - return release(); - }); +export function updateSituation(updatedSituation: any): Promise { + return db.fileOpWithLock(ufobFname, new Promise((resolve, reject) => { + getModel().then( + model => { + ufobModel.updateSituation(model, updatedSituation); + const validity = ufobMeta.validateModel(model); + if (validity.errors) { + error("Consistency error: updating of situation " + updatedSituation.s_id + " with " + JSON.stringify(updatedSituation) + " would brake the model."); + reject("Error on UFOB-B situation updating."); + } else { + writeModel(model).then( + () => resolve(), + error => reject(error) + ); + } + }, + error => reject(error) + ); + })); } -function loadSetSaveSituation(updatedSituation: any, next: (RestResult) => void) { - getModel().then((model) => { - ufobModel.updateSituation(model, updatedSituation); - const validity = ufobMeta.validateModel(model); - if (validity.errors) { - console.error("Consistency error: updating of situation " + updatedSituation.s_id + " with " + JSON.stringify(updatedSituation) + " would brake the model."); - next({"error": "Internal server error on UFOB-B situation updating."}); - } else { - writeModel(model); - next({"result": "ok"}); - } - }, (error) => { next({ "error": error, "s_id": updatedSituation.s_id }); }); +export function deleteSituation(s_id: Id): Promise { + return db.fileOpWithLock(ufobFname, new Promise((resolve, reject) => { + getModel().then( + model => { + ufobModel.deleteSituation(model, s_id); + writeModel(model).then( + () => deleteElementGraphics(s_id).then( + () => resolve(), + error => reject(error) + ), + error => reject(error) + ); + }); + })); } -export function deleteSituation(s_id: Id, next: (RestResult) => void) { - lock(ufobFname).then((release) => { - getModel().then((model) => { - ufobModel.deleteSituation(model, s_id); - writeModel(model); - next({"result": "ok"}); - }); - return release(); - }); +// Graphics + +function deleteElementGraphics(elId: Id): Promise { + return db.graphicsElementDelete(ufobGraphicsFname, elId); } diff --git a/server/logging.js b/server/logging.js new file mode 100644 index 0000000..b4d181a --- /dev/null +++ b/server/logging.js @@ -0,0 +1,8 @@ +// @flow + +const chalk = require('chalk'); + +export function error(msg: string): void { + console.error(chalk.bold.red(msg)); +} + diff --git a/shared/ajax.js b/shared/ajax.js new file mode 100644 index 0000000..f1cf741 --- /dev/null +++ b/shared/ajax.js @@ -0,0 +1,7 @@ +//@flow + +export type AjaxResponse = { + error: string +} | { + result: any +}; diff --git a/shared/model/ufoa.js b/shared/model/ufoa.js index ff68ce9..95f0e54 100644 --- a/shared/model/ufoa.js +++ b/shared/model/ufoa.js @@ -1,9 +1,10 @@ // @flow import * as R from 'ramda'; -import type { Id, Label } from '../metamodel/general'; -import type { UfoaEntity, Generalisation, GSet, Association, AssocType, AssocMeta, Connection, UfoaModel } from '../metamodel/ufoa'; +import type { Id } from '../metamodel/general'; +import type { UfoaEntity, Generalisation, GSet, Association, UfoaModel } from '../metamodel/ufoa'; import type { ValidationResult } from "../metamodel/general"; +import * as meta from '../metamodel/general'; import * as ufoaMeta from "../metamodel/ufoa"; import { getLastIdNo } from './general.js'; @@ -27,7 +28,7 @@ export function getEntity(model: UfoaModel, e_id: Id): ?UfoaEntity { export function updateEntity(model: UfoaModel, updatedEntity: UfoaEntity): ValidationResult { const validity = ufoaMeta.validateEntity(updatedEntity); if (validity.errors) { - return validity; + return validity.errors; } else { let entity = getEntity(model, updatedEntity.e_id); if (entity) { @@ -35,13 +36,18 @@ export function updateEntity(model: UfoaModel, updatedEntity: UfoaEntity): Valid } else { model.entities.push(updatedEntity); // added a new one to the model } - return ufoaMeta.validationResultOK; + return meta.validationResultOK; } } -export function deleteEntity(model: UfoaModel, e_id: Id): void { - let i = model.entities.findIndex(e => e.e_id === e_id); - model.entities.splice(i, 1); +export function deleteEntity(model: UfoaModel, e_id: Id): UfoaModel { + const entities2 = model.entities.filter(e => e.e_id !== e_id); + const associations2 = model.associations.filter(a => a.a_connection1.e_id !== e_id && a.a_connection2.e_id !== e_id); + return { + entities: entities2, + generalisations: R.clone(model.generalisations), + associations: associations2 + }; } // Generalisations @@ -99,7 +105,7 @@ export function updateGeneralisation(model: UfoaModel, updatedGeneralisation: Ge updateGSet(model, originalGSet.g_set_id, updatedGeneralisation.g_set); } } - return ufoaMeta.validationResultOK; + return meta.validationResultOK; } } @@ -165,7 +171,7 @@ export function updateAssociation(model: UfoaModel, updatedAssociation: Associat } else { model.associations.push(updatedAssociation); // added a new one to the model } - return ufoaMeta.validationResultOK; + return meta.validationResultOK; } } diff --git a/shared/urls.js b/shared/urls.js index 9ee8d1e..a4ef33c 100644 --- a/shared/urls.js +++ b/shared/urls.js @@ -11,22 +11,28 @@ if (process && process.env.NODE_ENV === "production") { // UFO-A export const ufoaGetModel = "/ufoa/getModel"; -export const ufoaGetGraphics = "/ufoa/getGraphics"; export const ufoaEntityUpdate = "/ufoa/entity/update"; -export const ufoaGraphicsSave = "/ufoa/saveGraphics"; -export const ufoaGraphicsDelete = "/ufoa/deleteGraphics"; export const ufoaEntityDelete = "/ufoa/entity/delete"; export const generalisationUpdate = "/ufoa/generalisation/update"; export const ufoaGeneralisationDelete = "/ufoa/generalisation/delete"; export const associationUpdate = "/ufoa/association/update"; export const ufoaAssociationDelete = "/ufoa/association/delete"; +// UFO-A Graphics + +export const ufoaGetGraphics = "/ufoa/getGraphics"; +export const ufoaGraphicsSave = "/ufoa/saveGraphics"; +export const ufoaGraphicsDelete = "/ufoa/deleteGraphics"; + // UFO-B export const ufobGetModel = "/ufob/getModel"; -export const ufobGetGraphics = "/ufob/getGraphics"; -export const ufobGraphicsSave = "/ufob/saveGraphics"; export const ufobEventUpdate = "/ufoa/event/update"; export const ufobSituationUpdate = "/ufoa/situation/update"; export const ufobEventDelete = "/ufob/event/delete"; export const ufobSituationDelete = "/ufob/situation/delete"; + +// UFO-B Graphics + +export const ufobGetGraphics = "/ufob/getGraphics"; +export const ufobGraphicsSave = "/ufob/saveGraphics";