pointsight/routes/api.route.ts

320 lines
12 KiB
TypeScript
Raw Normal View History

2022-03-06 18:36:36 +01:00
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;
}
});
}