module.exports = function (app, enabMods, con, otherContext) { const wc = require('pp-which-country'); const _ = require("underscore"); const libs = require("../libs/metaHandler.lib"); const jLib = require("../libs/jsonHand.lib"); const stringify = require('safe-stable-stringify') const mailValidator = require("deep-email-validator") const tools = require("../functions"); // Returns all installed and non-limited modules app.get("/api/allModules", function (req, res) { res.setHeader("Content-Type", "application/json"); const allModules = []; // Loop though all modules and sort all interesting ones into `allModules` for (let i = 0; i < enabMods.length; i++) { if (enabMods[i].getModuleMeta().limited == false) { allModules.push(enabMods[i].getModuleMeta()); } } // Return all modules res.send(allModules); }); // Returns all tags with usages amounts app.get("/api/allTags", function (req, res) { res.setHeader("Content-Type", "application/json"); // Return all tags const allTags = otherContext.tags //allTags = allTags.sort(function(a,b) { return parseInt(a.z) - parseInt(b.z) } ); const response = [] for (const key in allTags) { if (allTags.hasOwnProperty(key)) { console.log(`${key}: ${allTags[key]}`); response.push({key: key, amount: allTags[key]}) } } res.send(response); }); // The report API endpoint app.get("/api/internal/report", function (req, res) { res.setHeader("Content-Type", "application/json"); // First check if all needed parameters are set const point_id = req.query.point_id; const mail = req.query.mail; const reason = req.query.reason; if (!point_id || !mail || !reason) { res.send(JSON.stringify({ "status": "error", "message": "Missing parameters" })); } else { // Check if the point_id is valid const splited = point_id.split("_"); if (splited.length != 2) { res.send(JSON.stringify({ "status": "error", "message": "Invalid point_id" })); } else { let isValid = false; for (let i = 0; i < enabMods.length; i++) { if (enabMods[i].getModuleMeta().exactName == splited[0] && enabMods[i].getModuleMeta().limited == false) { isValid = true; } } if (isValid) { // Check if the mail is valid const mailValidationRes = mailValidator.validate({ email: mail, validateSMTP: false, validateTypo: false }); mailValidationRes.then(function (resp) { if (resp.valid) { const sqlQuery = "INSERT INTO `reports` (`point_id`, `mail`, `comment`) VALUES (?, ? , ?);"; con.query(sqlQuery, [point_id, mail, reason], function (err, rows, fields) { tools.handleMysqlErrors(err, "API"); res.send(JSON.stringify({ "status": "success", "message": "Report sent" })); }); } else { res.send(JSON.stringify({ "status": "error", "message": "Invalid mail", "cause": resp })); } }) } else { res.send(JSON.stringify({ "status": "error", "message": "Invalid point_id" })); } } } }); app.get("/api/retrieve", function (req, res) { // Make sure all parameters are there if ( req.query.uid != undefined ) { // All parameters are there res.setHeader("Content-Type", "application/json"); const uid = req.query.uid; let result = undefined; console.warn("Retrieving data for UID: " + uid); // Go thorugh all modules and find the one which should handle the request for (let i = 0; i < enabMods.length; i++) { if (enabMods[i].getModuleMeta().exactName == uid.split("_")[0] && enabMods[i].getModuleMeta().limited == false) { result = enabMods[i].queryItem(uid); console.warn("Found module: " + enabMods[i].getModuleMeta().exactName + " with result: " + result); } } // Because DBs are slow the module only returns a Promise and we have to wait for it Promise.all([result]).then(function (results) { res.send(results) }); } else { // A parameter is missing res.status(400); res.setHeader("Content-Type", "application/json"); res.send(JSON.stringify({ state: "Failed", message: "Missing arguments" })); } }); app.get("/api/getPOI", function (req, res) { // All parameters are there res.setHeader("Content-Type", "application/json"); // Check if the bounds are valid so `lat;lng` is present // First check if the `;` is present and .split() returns an array with 2 elements const boundNorthEast = req.query.boundingEast.split(";"); const boundSouthWest = req.query.boundingWest.split(";"); let filterdModules = []; if (boundNorthEast.length == 2 && boundSouthWest.length == 2) { // Length is valid. Now check if the values are numbers and they are not infinte if (_.isFinite(boundNorthEast[0]) && _.isFinite(boundNorthEast[1]) && _.isFinite(boundSouthWest[0]) && _.isFinite(boundSouthWest[1])) { // Values are valid const boundNorthEastLat = parseFloat(boundNorthEast[0]); const boundNorthEastLng = parseFloat(boundNorthEast[1]); const boundNorthEastLatLng = { lat: boundNorthEastLat, lng: boundNorthEastLng }; const boundSouthWestLat = parseFloat(boundSouthWest[0]); const boundSouthWestLng = parseFloat(boundSouthWest[1]); const boundSouthWestLatLng = { lat: boundSouthWestLat, lng: boundSouthWestLng }; // Get the country of both edges // If the country is diffrent, set the country to * const countryNorthEast = wc([boundNorthEastLng, boundNorthEastLat]); let countrySouthWest = wc([boundSouthWestLng, boundSouthWestLat]); if (countryNorthEast != countrySouthWest) { // Country is the same countrySouthWest = "*"; } // Get all POIs in the given bounds const usefullMods = [] for (let i = 0; i < enabMods.length; i++) { const meta = enabMods[i].getModuleMeta() // Is the country in the module's country list? Or is it "*"? Or did the system decide is doesnt matter if ((meta.country.indexOf(countrySouthWest) > -1 || meta.country[0] == "*" || countrySouthWest == "*") && meta.limited == false) { usefullMods.push(enabMods[i]) } } // JSON filter if (jLib.IsJsonString(req.query.filter)) { const jsonData = JSON.parse(req.query.filter); filterdModules = usefullMods.filter(function (elm) { // Loops through all elements in a list and lets you decide if weather to keep 'em or not let amount = 0; for (const fId in jsonData.filters) { // Do this is each provided filter const fi = jsonData.filters[fId]; // Gets the current filters name switch (fi[0]) { case "tag": if (jsonData.conjunction == "OR") { if (libs.returnTags(elm).includes(fi[1])) { return elm; } else { break; } } else { if (libs.returnTags(elm).includes(fi[1])) { amount++; } break; } case "country": if (jsonData.conjunction == "OR") { if (libs.returnCountries(elm).includes(fi[1])) { return elm; } else { break; } } else { if (libs.returnCountries(elm).includes(fi[1])) { amount++; } break; } case "source": if (jsonData.conjunction == "OR") { if (elm.getModuleMeta().exactName == fi[1]) { return elm; } else { break; } } else { if (elm.getModuleMeta().exactName == fi[1]) { amount++; } break; } } } if (jsonData.conjunction == "AND") { if (amount == jsonData.filters.length) { return elm; } } }); } else { // No filtering filterdModules = enabMods; } // Create all promises const allProms = []; // A list for all promises for (let i = 0; i < filterdModules.length; i++) { const module = filterdModules[i]; const temp = module.queryData(boundNorthEastLatLng, boundSouthWestLatLng, true); // Returns a promise of the results, because DBs are slowwwww allProms.push(temp); // Put the promises into a list } // Wait for all promises and return them Promise.all(allProms).then(function (result) { const allResultsInOne = [] for (let i = 0; i < result.length; i++) { for (let d = 0; d < result[i].length; d++) { allResultsInOne.push(result[i][d]) } } res.send(stringify(allResultsInOne)); }).catch(function (error) { console.error(error) res.status(500).send(error); // We should probably not do this in a PROD env but FIXME: Only in DEV env }); } else { // Values are not valid res.status(400); res.send(JSON.stringify({ state: "Failed", message: "Bounding box is not valid" })); return (0); } } else { res.send( JSON.stringify({ state: "Failed", message: "Invalid arguments" }) ); res.status(400); return; } }); app.get("/api/getPOILocations", function (req, res) { // Make sure all parameters are there // All parameters are there res.setHeader("Content-Type", "application/json"); if (_.isFinite(req.query.lat) && _.isFinite(req.query.lng) && _.isFinite(req.query.radius)) { const lng = parseFloat(req.query.lng); const lat = parseFloat(req.query.lat); const radius = parseFloat(req.query.radius); // Filter by usefull modules const country = wc([lng, lat]); // Find out which country is at this location const usefullMods = []; // Go through all modules and find all fiting ones for (let i = 0; i < enabMods.length; i++) { const meta = enabMods[i].getModuleMeta() if ((meta.country.indexOf(country) > -1 || meta.country[0] == "*") && meta.limited == false) { usefullMods.push(enabMods[i]) } } const allProms = []; for (let i = 0; i < usefullMods.length; i++) { const module = usefullMods[i] const temp = module.queryData(lat, lng, radius) // Returns a promise of the results allProms.push(temp) } // Wait for all promises to be resolved Promise.all(allProms).then(function (result) { const allResultsInOne = [] for (let i = 0; i < result.length; i++) { for (let d = 0; d < result[i].length; d++) { allResultsInOne.push(result[i][d]) } } res.send(allResultsInOne); }).catch(function (error) { console.error(error) res.status(500).send(error); // TODO: again only do it in DEV envs }); } else { res.send( JSON.stringify({ state: "Failed", message: "Invalid arguments" }) ); res.status(400); return; } }); }