UNPKG

node-red-contrib-snap4city-user

Version:

Nodes for Snap4city project, targeted to standard user (no developer)

970 lines (804 loc) 34 kB
<!--/* NODE-RED-CONTRIB-SNAP4CITY-USER Copyright (C) 2018 DISIT Lab http://www.disit.org - University of Florence This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */--> <style> .myAddButton { -moz-box-shadow: inset 0px 1px 0px 0px #ffffff; -webkit-box-shadow: inset 0px 1px 0px 0px #ffffff; box-shadow: inset 0px 1px 0px 0px #ffffff; background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #f9f9f9), color-stop(1, #e9e9e9)); background: -moz-linear-gradient(top, #f9f9f9 5%, #e9e9e9 100%); background: -webkit-linear-gradient(top, #f9f9f9 5%, #e9e9e9 100%); background: -o-linear-gradient(top, #f9f9f9 5%, #e9e9e9 100%); background: -ms-linear-gradient(top, #f9f9f9 5%, #e9e9e9 100%); background: linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f9f9', endColorstr='#e9e9e9', GradientType=0); background-color: #f9f9f9; -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; border: 1px solid #dcdcdc; display: inline-block; cursor: pointer; color: #666666; font-family: Arial; font-size: 12px; font-weight: bold; padding: 6px 6px; margin-bottom: 3px; margin-top: 3px; text-decoration: none; text-shadow: 0px 1px 0px #ffffff; } .myAddButton:hover { background: -webkit-gradient(linear, left top, left bottom, color-stop(0.05, #e9e9e9), color-stop(1, #f9f9f9)); background: -moz-linear-gradient(top, #e9e9e9 5%, #f9f9f9 100%); background: -webkit-linear-gradient(top, #e9e9e9 5%, #f9f9f9 100%); background: -o-linear-gradient(top, #e9e9e9 5%, #f9f9f9 100%); background: -ms-linear-gradient(top, #e9e9e9 5%, #f9f9f9 100%); background: linear-gradient(to bottom, #e9e9e9 5%, #f9f9f9 100%); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e9e9e9', endColorstr='#f9f9f9', GradientType=0); background-color: #e9e9e9; } .myAddButton:active { position: relative; top: 1px; } .myAddButton:focus { outline: 0 !important; background-color: #e9e9e9; } .myCheckButton { background-color: #44c767; -moz-border-radius: 28px; -webkit-border-radius: 28px; border-radius: 28px; border: 1px solid #18ab29; display: inline-block; cursor: pointer; color: #ffffff; font-family: Arial; font-size: 17px; padding: 10px 25px; margin-bottom: 15px; margin-top: 15px; text-decoration: none; text-shadow: 0px 1px 0px #2f6627; } .myCheckButton:hover { background-color: #5cbf2a; } .myCheckButton:active { position: relative; top: 1px; } /*################################*/ </style> <!-- Copyright 2013, 2016 IBM Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <script type="text/x-red" data-help-name="device-registration-user"> </script> <script type="text/javascript"> RED.nodes.registerType('device-registration-user', { category: 'S4CIoT', color: //function() { //return nodeColor()|| '#a6bbcf'; //}, '#a6bbcf', defaults: { name: { value: "" }, authentication: { type: "snap4city-authentication", required: false }, modcom: { required: true }, motivation: { required: true }, latitude: { value: 0.0, required: false, validate: RED.validators.number() }, longitude: { value: 0.0, required: false, validate: RED.validators.number() }, range: { value: "", required: false }, maxdists: { value: 1, required: false, validate: RED.validators.number() }, maxresults: { value: 100, required: false, validate: RED.validators.number() } }, inputs: 0, outputs: 0, icon: "white-globe.png", label: function () { return this.name || "device-registration-user"; }, oneditprepare: function () { $("#node-input-currentNodeId").val(this.id); var accessToken = ""; $.ajax({ url: "retrieveAccessTokenAuthentication", type: "POST", async: false, dataType: "json", data: { "authenticationNodeId": $("#node-input-authentication").val(), "nodeId": $("#node-input-currentNodeId").val() }, success: function (_data) { if (_data.accessToken == "") { $("#deviceRegistrationUserContainer").hide(); $('#tipAuthenticationWrong').show(); $('#tipAuthentication').hide(); } } }); isSuccess = 0; var node = this; this._def.color = '#a6bbcf'; console.log(this); console.log(this._def.color); isdone = false; ischecked = false; allData = []; devicetype = ""; contextbroker = ""; protocol = ""; format = ""; healthiness_criteria = ""; healthiness_value = ""; attributes = []; kind = ""; producer = ""; frequency = ""; k1 = generateUUID(); k2 = generateUUID(); $('#node-input-k-label-normal').hide(); $('#node-input-k-label-sigfox').hide(); //in case no data received, so none of these appears, otherwise they will both appear $("#node-dialog-ok").css('background', '#FFFFFF').css('border-color', '#A9A9A9'); addAsMendatoryListener('node-input-name'); //addAsMendatoryListener('node-input-devicetype'); addAsMendatoryListener('node-input-model'); addAsMendatoryListener('node-input-k1'); addAsMendatoryListener('node-input-k2'); //$('#node-dialog-ok').button("disable"); var pos = $("#node-dialog-ok").position(); var w = $("#node-dialog-ok").width(); var h = $("#node-dialog-ok").height(); coverDiv = document.createElement('div'); coverDiv.style.position = 'absolute'; coverDiv.style.top = pos.top + "px"; coverDiv.style.left = pos.left + "px"; coverDiv.style.width = w * 2 + "px"; coverDiv.style.height = h * 2 + "px"; coverDiv.style.background = "none"; coverDiv.style.outline = "none"; coverDiv.style.opacity = "0%"; console.log("Top: " + pos.top + " Left: " + pos.left + " width: " + w + " height: " + h); var parentDiv = $("#node-dialog-ok").parents(); console.log("parentNode " + parentDiv[0]); parentDiv[0].appendChild(coverDiv); coverDiv.onclick = function () { console.log("here?"); if (isdone) { $("#node-dialog-ok").simulate('click'); } else { alert("Please validate your device first by clicking on the 'Check' button"); } }; addonChangeListener(''); $.ajax({ url: "s4c/js/leaflet.js", async: false, dataType: "script" }); $.ajax({ url: "s4c/js/leaflet.draw.js", async: false, dataType: "script" }); node = this; map = L.map('node-input-map').setView([43.78, 11.23], 9); L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); window.node_input_map = map; var mapLayers = {}; drawnItems = new L.FeatureGroup(); map.addLayer(drawnItems); var editControl = new L.Control.Draw({ draw: false, edit: { remove: false, featureGroup: drawnItems } }); map.addControl(editControl); drawControl = new L.Control.Draw({ remove: false, draw: { position: 'topleft', polyline: false, marker: { icon: new L.DivIcon({ iconSize: new L.Point(8, 8), className: 'leaflet-div-icon leaflet-editing-icon test' }) }, circlemarker: false, circle: false, polygon: false, rectangle: false } }); map.addControl(drawControl); L.control.layers(mapLayers, { 'drawlayer': drawnItems }, { collapsed: true }).addTo(map); map.on(L.Draw.Event.CREATED, function (e) { somethingChanged(); var fence = e.layer; fence.nodeID = node.id; if (drawnItems.hasLayer(fence) == false) { drawnItems.addLayer(fence); } drawControl.remove(); markers = {}; drawnItems.eachLayer(function (layer) { markers[layer.nodeID] = layer.toGeoJSON(); }); $("#node-input-devicelatitude").val(markers[node.id].geometry.coordinates[1]); $("#node-input-devicelongitude").val(markers[node.id].geometry.coordinates[0]); }); map.on('draw:edited', function (e) { somethingChanged(); var fences = e.layers; fences.eachLayer(function (fence) { fence.shape = "geofence"; if (drawnItems.hasLayer(fence) == false) { drawnItems.addLayer(fence); } }); markers = {}; drawnItems.eachLayer(function (layer) { markers[layer.nodeID] = layer.toGeoJSON(); }); $("#node-input-devicelatitude").val(markers[node.id].geometry.coordinates[1]); $("#node-input-devicelongitude").val(markers[node.id].geometry.coordinates[0]); }); /*map.on('draw:deleted', function(e) { somethingChanged(); drawControl.addTo(map); $("#node-input-devicelatitude").val(0); $("#node-input-devicelongitude").val(0); });*/ L.Control.RemoveAll = L.Control.extend({ options: { position: 'topleft', }, onAdd: function (map) { var controlDiv = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar'); L.DomEvent .addListener(controlDiv, 'click', L.DomEvent.stopPropagation) .addListener(controlDiv, 'click', L.DomEvent.preventDefault) .addListener(controlDiv, 'click', function () { drawnItems.clearLayers(); somethingChanged(); drawControl.addTo(map); $("#node-input-devicelatitude").val(0); $("#node-input-devicelongitude").val(0); }); var controlUI = L.DomUtil.create('a', 'leaflet-draw-edit-remove', controlDiv); controlUI.title = 'Delete'; controlUI.href = '#'; return controlDiv; } }); var removeAllControl = new L.Control.RemoveAll(); map.addControl(removeAllControl); var string = { value: "string", label: "string:" }; var int = { value: "integer", label: "int:" }; var float = { value: "float", label: "float:" }; var supportedTypes = [string, int, float]; $.ajax({ //url: "http://iotdirectory.snap4city.org/api/contextbroker.php?action=get_all_contextbroker", //url: "http://iotdirectory.snap4city.org/api/contextbroker.php?action=get_default", url: "https://iot-app.snap4city.org/iotdirectory/iot2/api/model.php?action=get_models", type: "GET", async: false, dataType: "json", success: function (data) { if (data.status == 'ok') { console.log(data); allData = data.content; var models = data.content; for (var i = 0; i < models.length; i++) { $("<option value=\"" + models[i].id + "\">" + models[i].name + "</option>").appendTo($("#node-input-model")); } modelChanged(); } else { console.log(data.status); } }, error: function (err) { console.log("error in context broker is " + err); } }); // }); }, oneditsave: function () { console.log(" in editsave, is done is: " + isdone); if (!isdone) { return; } console.log("It seems that isdone is true so here I am"); sendToServer(this.id); }, oneditresize: function () { if (window.node_input_map) { window.node_input_map.invalidateSize(true); } var pos = $("#node-dialog-ok").position(); var w = $("#node-dialog-ok").width(); var h = $("#node-dialog-ok").height(); var parentDiv = $("#node-dialog-ok").parents(); parentDiv[0].removeChild(coverDiv); coverDiv = document.createElement('div'); coverDiv.style.id = 'coverDiv'; coverDiv.style.position = 'absolute'; coverDiv.style.top = pos.top + "px"; coverDiv.style.left = pos.left + "px"; coverDiv.style.width = w * 2 + "px"; coverDiv.style.height = h * 2 + "px"; coverDiv.style.background = "none"; coverDiv.style.outline = "none"; coverDiv.style.opacity = "0%"; console.log("Top: " + pos.top + " Left: " + pos.left + " width: " + w + " height: " + h); console.log("parentNode " + parentDiv[0]); parentDiv[0].appendChild(coverDiv); coverDiv.onclick = function () { console.log("here?"); if (isdone) { $("#node-dialog-ok").simulate('click'); } else { alert("Please validate your device first by clicking on the 'Check' button"); } }; }, }); function generateUUID() { // Public Domain/MIT var d = new Date().getTime(); if (typeof performance !== 'undefined' && typeof performance.now === 'function') { d += performance.now(); //use high-precision timer if available } return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); }); } function addAsMendatoryListener(fieldId) { $('#' + fieldId).change(function () { checkIfAllMendatoriesOk(); }); } function checkIfAllMendatoriesOk() { console.log(typeof ($("#node-input-name").val())); console.log(typeof ($("#node-input-model").val())); if (typeof ($("#node-input-name").val()) != "undefined" && typeof ($("#node-input-model").val()) != "undefined") { if ($("#node-input-name").val().length == 0 || $("#node-input-model").val().length == 0 || $( '#node-input-k1').val() == "" || $('#node-input-k2').val() == "") { $("#node-dialog-ok").css('background', '#FFFFFF').css('border-color', '#A9A9A9'); ischecked = false; isdone = false; } else { $("#node-dialog-ok").css('background', '#FFFFFF').css('border-color', '#A9A9A9'); ischecked = true; isdone = false; } } } /* function addFunction(){ var box= $("#node-input-attrs-container") box.editableList('addItem'); somethingChanged(); }*/ function checkFunction() { console.log("checking"); if (ischecked) { checkRequest(); } else { alert("Please fill in the empty fields. The required fields are marked with *"); } } function addonChangeListener(fieldId) { $('#' + fieldId).change(function () { somethingChanged(); }); } function somethingChanged() { $("#node-dialog-ok").css('background', '#FFFFFF').css('border-color', '#A9A9A9'); isdone = false; console.log("something changed"); } function modelChanged() { $("#node-dialog-ok").css('background', '#FFFFFF').css('border-color', '#A9A9A9'); isdone = false; console.log("model changed"); if (allData.length > 0) { var selectedModel = $("#node-input-model").val(); console.log("selectedModel: " + selectedModel); for (var i = 0; i < allData.length; i++) { if (allData[i].id == selectedModel) { devicetype = allData[i].devicetype; contextbroker = allData[i].contextbroker; protocol = allData[i].protocol; format = allData[i].format; healthiness_criteria = allData[i].healthiness_criteria; healthiness_value = allData[i].healthiness_value; attributes = allData[i].attributes; kind = allData[i].kind; producer = allData[i].producer; frequency = allData[i].frequency; break; } } if (selectedModel == "5") //SigFox { $('#node-input-k1').val(""); $('#node-input-k2').val(""); $('#node-input-k-label-normal').hide(); $('#node-input-k-label-sigfox').show(); $('#node-input-k1').removeAttr('disabled'); $('#node-input-k2').removeAttr('disabled'); } else { $('#node-input-k1').val(k1); $('#node-input-k2').val(k2); $('#node-input-k-label-normal').show(); $('#node-input-k-label-sigfox').hide(); $('#node-input-k1').attr({ 'disabled': 'disabled' }); $('#node-input-k2').attr({ 'disabled': 'disabled' }); } } } function nodeColor() { if (isSuccess == 1) { return '#87A980'; } else if (isSuccess == -1) { return '#E9967A'; } else { return '#a6bbcf'; } } function disable() { var inputs = document.getElementsByTagName('input'); var len = inputs.length; console.log(inputs); for (var i = 0; i < len; i++) { inputs[i].disabled = true; } var selects = document.getElementsByTagName('select'); var len = selects.length; console.log(selects); for (var i = 0; i < len; i++) { selects[i].disabled = true; } } function sendToServer(id) { var accessToken = ""; $.ajax({ url: "retrieveAccessTokenAuthentication", type: "POST", async: false, dataType: "json", data: { "authenticationNodeId": $("#node-input-authentication").val(), "nodeId": $("#node-input-currentNodeId").val() }, success: function (_data) { if (_data.accessToken == "") { //VEDERE COSA FARE IN QUESTO CASO } else { accessToken = _data.accessToken; }; } }); var accesstoken = accessToken; var payload = {}; console.log("k1 " + $("#node-input-k1").val()); console.log("k2 " + $("#node-input-k2").val()); if (accesstoken != "") { try { //var accesstoken = ""; console.log("in retrieving access token"); console.log("this.id " + id); /* $.ajax({ url: "deviceregistration/" + id, type: "GET", async: false, success: function (resp) { console.log(resp); accesstoken = resp.accessToken; */ var payload = { action: "insert", attributes: attributes, // JSON.stringify(mynewAttributes), id: $("#node-input-name").val(), type: devicetype, //$("#node-input-devicetype").val(), kind: kind, //$("#node-input-devicekind").val(), contextbroker: contextbroker, //$("#node-input-contextbroker").val(), protocol: protocol, //nameprotocol, format: format, // nameformat, healthiness_criteria: healthiness_criteria, healthiness_value: healthiness_value, mac: "", model: "", //$("#node-input-devicemodel").val(), producer: producer, // $("#node-input-deviceproducer").val(), latitude: $("#node-input-devicelatitude").val(), longitude: $("#node-input-devicelongitude").val(), visibility: "private", owner: "marco", frequency: frequency, //"0" nodered: "yes", token: accesstoken, k1: $("#node-input-k1").val(), k2: $("#node-input-k2").val() }; $.ajax({ url: "https://iotdirectory.snap4city.org/api/device.php", type: "POST", data: payload, dataType: "json", success: function (data) { console.log("success" + JSON.stringify(data)); if (data.status == "ok") { alert("Your device registration has been done!"); isdone = true; isSuccess = 1; } else { alert("Your device registration is not valid. " + data.msg + " Please try again!"); isdone = false; isSuccess = -1; } if (isdone) { $("#node-dialog-ok").css('background', '#A81A31').css( 'border-color', '#A81A31'); } }, error: function (data) { console.log("error"); console.log(data); // if( isdone){ //NODE._def.color= '#E9967A'; alert("Your device registration has failed! please try again"); // } // else{ // alert("Your device registration is not valid. The device name already exists, please choose another one and try again!"); // } console.log("Ko result: " + JSON.stringify(data)); isdone = false; isSuccess = -1; } }); /* }, error: function (jqXHR, textStatus, errorThrown) { console.log("ERROR"); } }); */ } catch (err) { console.log("error in access token " + err); } } // MM: 0905 beginning //console.log(payload); } function checkRequest() { var payload = { action: 'exist_device', id: $("#node-input-name").val(), contextbroker: contextbroker, //$("#node-input-contextbroker").val() }; $.ajax({ url: "https://iotdirectory.snap4city.org/api/device.php", type: "GET", data: payload, //JSON.stringify(payload), //dataType: "json", success: function (data) { console.log("success"); console.log(data); if (data.status == 'ok') { if (data.content == 0) { alert("Your device registration is valid, you can proceed."); isdone = true; isSuccess = 1; } else { alert( "Your device registration is not valid. The device name already exists, please choose another one and try again!" ); isdone = false; isSuccess = -1; } } else { alert("An error occured, please try again later"); isdone = false; isSuccess = -1; } if (isdone) { $("#node-dialog-ok").css('background', '#A81A31').css('border-color', '#A81A31'); } }, error: function (data) { alert("An error occured please try again later"); console.log("Ko result: " + JSON.stringify(data)); isdone = false; isSuccess = -1; } }); } </script> <script type="text/x-red" data-template-name="device-registration-user"> <input type="hidden" id="node-input-currentNodeId"> <div class="form-row" id="rowAuthentication"> <label for="node-input-authentication">Authentication</label> <input type="text" id="node-input-authentication"> </div> <div class="form-tips" id="tipAuthentication" style="max-width: none"> You must have an account with Snap4city to use this node. You can register for one <a href="https://www.snap4city.org" target="_blank">here</a>. </div> <div class="form-tips" id="tipAuthenticationWrong" style="display:none; max-width: none"> Maybe the authentication data are wrong. Check them and redeploy the node. </div> <div class="form-tips" id="tipAuthenticationRedeploy" style="display:none; max-width: none"> Deploy the node to retrieve the updated list of IoT Devices. </div> <div class="form-tips" id="tipAuthenticationDeployFirstTime" style="display:none; max-width: none"> Insert the authentication data and deploy the node to retrieve the updated list of IoT Devices. </div> <div id="deviceRegistrationUserContainer"> <div class="form-row" id="child"> <label for="node-input-name"> <i class="fa"></i> Device Name <sup> <b>*</b> </sup>:</label> <input type="text" id="node-input-name"> </div> <div class="form-row"> <label for="node-input-model"> <i class="fa"></i>Model</label> <select id="node-input-model" onchange="modelChanged()"> </select> </div> <!-- <div class="form-row"> <label for="node-input-devicetype"><i class="fa"></i>Device Type<sup><b>*</b></sup>:</label> <input type="text" id="node-input-devicetype"> </div>--> <div class="form-row"> <link rel="stylesheet" href="s4c/css/leaflet.css" /> <link rel="stylesheet" href="s4c/css/leaflet.draw.css" /> <div id="node-input-map" style="height: 400px"></div> </div> <!--<div class="form-row"> <label for="node-input-devicekind"><i class="fa"></i>Device Kind</label> <select id="node-input-devicekind" onchange="somethingChanged()"> <option value="sensor">Sensor</option> <option value="actuator">Actuator</option> </select> </div> <div class="form-row" style="display:none" > <label for="node-input-devicemac"><i class="fa"></i>Device MAC</label> <input type="text" id="node-input-devicemac"> </div> <div class="form-row"> <label for="node-input-devicemodel"><i class="fa"></i>Device Model</label> <input type="text" id="node-input-devicemodel" onchange="somethingChanged()"> </div> <div class="form-row"> <label for="node-input-deviceproducer"><i class="fa"></i>Device Producer</label> <input type="text" id="node-input-deviceproducer" onchange="somethingChanged()"> </div>--> <div class="form-row" style="display:none"> <label for="node-input-devicelatitude"> <i class="fa"></i>Device Latitude</label> <input type="text" id="node-input-devicelatitude" disabled> </div> <div class="form-row" style="display:none"> <label for="node-input-devicelongitude"> <i class="fa"></i>Device Longitude</label> <input type="text" id="node-input-devicelongitude" disabled> </div> <div class="form-row" style="margin-top:20px"> <label for="node-input-k1"> <i class="fa"></i>Key 1 <sup> <b>*</b> </sup> </label> <input type="text" id="node-input-k1" disabled> </div> <div class="form-row"> <label for="node-input-k2"> <i class="fa"></i>Key 2 <sup> <b>*</b> </sup> </label> <input type="text" id="node-input-k2" disabled> </div> <div> <p id="node-input-k-label-normal" style="font-size:12px; color:#808080"> <i class="fa"></i>These keys have been generated automatically for your device. Keep track of them. Details on <a style="font-size:12px; align-left: " href="https://www.snap4city.org/drupal/node/76">info</a> </p> </div> <div> <p id="node-input-k-label-sigfox" style="font-size:12px; color:#808080"> <i class="fa"></i>Generate in your SigFox server the keys and report them here. Details on <a style="font-size:12px; align-left: " href="https://www.snap4city.org/drupal/node/76">info</a> </p> </div> <!-- <div class="form-row node-input-attrs-container-row"> <label for="node-input-attrs-container"><i class="fa"></i> Value:</label> <button id="addbutton" class="myAddButton" onclick="addFunction()"><b>+</b> add</button> <ol id="node-input-attrs-container"></ol> </div>--> <div> <button id="checkbutton" class="myCheckButton" onclick="checkFunction()">Check!</button> </div> <div id="done-cover" width="0px" height="0px></div> </div> </script>