diff --git a/API/Backend/Draw/routes/draw.js b/API/Backend/Draw/routes/draw.js index 703d0bba..cd179b02 100644 --- a/API/Backend/Draw/routes/draw.js +++ b/API/Backend/Draw/routes/draw.js @@ -12,6 +12,10 @@ const UserfilesTEST = ufiles.UserfilesTEST; const uf = require("../models/userfeatures"); const Userfeatures = uf.Userfeatures; const UserfeaturesTEST = uf.UserfeaturesTEST; + +const filesutils = require("./filesutils"); +const getfile = filesutils.getfile; + const { sequelize } = require("../../../connection"); const router = express.Router(); @@ -444,6 +448,123 @@ const clipUnder = function ( failureCallback(err); }); }; + +const _templateConform = (req) => { + return new Promise((resolve, reject) => { + req.body.id = req.body.file_id + + getfile(req, { send: (r) => { + if( r.status === 'success') { + const geojson = r.body.geojson + const template = r.body.file?.[0]?.dataValues?.template?.template || [] + const existingProperties = JSON.parse(req.body.properties || '{}') + const templaterProperties = {} + + template.forEach((t, idx) => { + switch (t.type) { + case 'incrementer': + const nextIncrement = + _getNextIncrement( + existingProperties[t.field], + t, + geojson.features, + existingProperties + ) + if (nextIncrement.error != null) { + reject(nextIncrement.error) + return + } + else templaterProperties[t.field] = nextIncrement.newValue + break; + default: + } + }) + + req.body.properties = JSON.stringify({ ...existingProperties, ...templaterProperties }) + } + resolve() + return + }}) + + function _getNextIncrement(value, t, layer, existingProperties) { + const response = { + newValue: value, + error: null, + } + + let usedValues = [] + const split = (t._default || t.default).split('#') + const start = split[0] + const end = split[1] + + for (let i = 0; i < layer.length; i++) { + if (layer[i] == null) continue + let geojson = layer[i] + if (geojson?.properties?.[t.field] != null) { + let featuresVal = geojson?.properties?.[t.field] + + featuresVal = featuresVal.replace(start, '').replace(end, '') + + if (featuresVal !== '#') { + featuresVal = parseInt(featuresVal) + usedValues.push(featuresVal) + } + } + } + + if ((response.newValue || '').indexOf('#') !== -1) { + // Actually increment the incrementer for the first time + let bestVal = 0 + usedValues.sort(function (a, b) { + return a - b + }) + usedValues = [...new Set(usedValues)] // makes it unique + usedValues.forEach((v) => { + if (bestVal === v) bestVal++ + }) + response.newValue = response.newValue.replace('#', bestVal) + } else if (existingProperties) { + let numVal = response.newValue.replace(start, '').replace(end, '') + if (numVal != '#') { + numVal = parseInt(numVal) + if (existingProperties[t.field] === response.newValue) { + // In case of a resave, make sure the id exists only once + let count = 0 + usedValues.forEach((v) => { + if (numVal === v) count++ + }) + if (count > 1) + response.error = `Incrementing field: '${t.field}' is not unique` + } else { + // In case a manual change, make sure the id is unique + if (usedValues.indexOf(numVal) !== -1) + response.error = `Incrementing field: '${t.field}' is not unique` + } + } + } + + // Check that the field still matches the surrounding string + const incRegex = new RegExp(`^${start}\\d+${end}$`) + if (incRegex.test(response.newValue) == false) { + response.error = `Incrementing field: '${t.field}' must follow syntax: '${start}{#}${end}'` + } + + // Check that incrementer is unique + for (let i = 0; i < layer.length; i++) { + if (layer[i] == null) continue + let geojson = layer[i] + if (geojson?.properties?.[t.field] != null) { + let featuresVal = geojson?.properties?.[t.field] + if ((response.newValue || '').indexOf('#') == -1 && response.newValue === featuresVal) { + response.error = `Incrementing field: '${t.field}' is not unique` + } + } + } + + return response + } + }) +} /** * Adds a feature * { @@ -457,13 +578,23 @@ const clipUnder = function ( * geometry: (required) * } */ -const add = function ( +const add = async function ( req, res, successCallback, failureCallback1, failureCallback2 ) { + let failedTemplate = false; + await _templateConform(req).catch(err => { + failedTemplate = err + }) + if( failedTemplate !== false) { + if (typeof failureCallback2 === "function") + failureCallback2(failedTemplate); + return + } + let Files = req.body.test === "true" ? UserfilesTEST : Userfiles; let Features = req.body.test === "true" ? UserfeaturesTEST : Userfeatures; let Histories = req.body.test === "true" ? FilehistoriesTEST : Filehistories; @@ -670,7 +801,17 @@ router.post("/add", function (req, res, next) { * geometry: (optional) * } */ -const edit = function (req, res, successCallback, failureCallback) { +const edit = async function (req, res, successCallback, failureCallback) { + let failedTemplate = false; + await _templateConform(req).catch(err => { + failedTemplate = err + }) + if( failedTemplate !== false) { + if (typeof failureCallback === "function") + failureCallback(failedTemplate); + return + } + let Files = req.body.test === "true" ? UserfilesTEST : Userfiles; let Features = req.body.test === "true" ? UserfeaturesTEST : Userfeatures; let Histories = req.body.test === "true" ? FilehistoriesTEST : Filehistories; @@ -832,7 +973,9 @@ router.post("/edit", function (req, res) { res.send({ status: "failure", message: "Failed to edit feature.", - body: {}, + body: { + error: err + }, }); } ); diff --git a/src/essence/Tools/Draw/DrawTool_Editing.js b/src/essence/Tools/Draw/DrawTool_Editing.js index 2009e8f2..dd3e65a8 100644 --- a/src/essence/Tools/Draw/DrawTool_Editing.js +++ b/src/essence/Tools/Draw/DrawTool_Editing.js @@ -5,6 +5,7 @@ import LayerGeologic from '../../Basics/Layers_/LayerGeologic/LayerGeologic' import Globe_ from '../../Basics/Globe_/Globe_' import Map_ from '../../Basics/Map_/Map_' import UserInterface_ from '../../Basics/UserInterface_/UserInterface_' +import CursorInfo from '../../Ancillary/CursorInfo' import turf from 'turf' import DrawTool_Templater from './DrawTool_Templater' @@ -2333,7 +2334,17 @@ var Editing = { if (DrawTool.isReviewOpen) DrawTool.showReview() }, - function () { + function (err) { + CursorInfo.update( + `${err.message}${ + err.body?.error + ? ` - ${err.body.error}` + : '' + }`, + 6000, + true, + { x: 305, y: 6 } + ) $('.drawToolContextMenuSave').css( 'background', '#ff2626' @@ -2468,7 +2479,17 @@ var Editing = { if (DrawTool.isReviewOpen) DrawTool.showReview() } })(newProperties, newGeometry, featureType, fileid), - function () { + function (err) { + CursorInfo.update( + `${err.message}${ + err.body?.error + ? ` - ${err.body.error}` + : '' + }`, + 6000, + true, + { x: 305, y: 6 } + ) $('.drawToolContextMenuSave').css( 'background', '#ff2626' @@ -2536,7 +2557,17 @@ var Editing = { }, 2) } })(l, l.file.id, l.properties._.id, newProperties), - function () { + function (err) { + CursorInfo.update( + `${err.message}${ + err.body?.error + ? ` - ${err.body.error}` + : '' + }`, + 6000, + true, + { x: 305, y: 6 } + ) $('.drawToolContextMenuSave').css( 'background', '#ff2626' diff --git a/src/essence/Tools/Draw/DrawTool_Templater.js b/src/essence/Tools/Draw/DrawTool_Templater.js index 586c4885..62336481 100644 --- a/src/essence/Tools/Draw/DrawTool_Templater.js +++ b/src/essence/Tools/Draw/DrawTool_Templater.js @@ -358,7 +358,7 @@ const DrawTool_Templater = { ).val() const nextIncrement = - DrawTool_Templater._getNextIncrement( + DrawTool_Templater._validateIncrement( values[t.field], t, layer, @@ -462,7 +462,7 @@ const DrawTool_Templater = { * @param {*} layer * @returns {newValue: Number, error: String} */ - _getNextIncrement(value, t, layer, existingProperties) { + _validateIncrement(value, t, layer, existingProperties) { const response = { newValue: value, error: null, @@ -500,7 +500,6 @@ const DrawTool_Templater = { usedValues.forEach((v) => { if (bestVal === v) bestVal++ }) - response.newValue = response.newValue.replace('#', bestVal) } else if (existingProperties) { let numVal = response.newValue.replace(start, '').replace(end, '') if (numVal != '#') { @@ -1238,7 +1237,7 @@ const DrawTool_Templater = { switch (t.type) { case 'incrementer': const nextIncrement = - DrawTool_Templater._getNextIncrement( + DrawTool_Templater._validateIncrement( t.default, t, layer