Compare commits
No commits in common. "develop" and "master" have entirely different histories.
@ -1,2 +0,0 @@
|
|||||||
node_modules
|
|
||||||
npm-debug.log
|
|
||||||
6
.gitignore
vendored
@ -1,7 +1,3 @@
|
|||||||
# credentials
|
|
||||||
.env
|
|
||||||
config.json
|
|
||||||
|
|
||||||
# compiled output
|
# compiled output
|
||||||
/dist
|
/dist
|
||||||
|
|
||||||
@ -25,5 +21,3 @@ config.json
|
|||||||
# System Files
|
# System Files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
node_modules
|
|
||||||
2
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/workspace.xml
|
||||||
12
.idea/cc-data.iml
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/frontend/dist" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/frontend/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
16
.idea/checkstyle-idea.xml
generated
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CheckStyle-IDEA">
|
||||||
|
<option name="configuration">
|
||||||
|
<map>
|
||||||
|
<entry key="checkstyle-version" value="8.30" />
|
||||||
|
<entry key="copy-libs" value="true" />
|
||||||
|
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
|
||||||
|
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
|
||||||
|
<entry key="scan-before-checkin" value="false" />
|
||||||
|
<entry key="scanscope" value="JavaOnly" />
|
||||||
|
<entry key="suppress-errors" value="false" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
6
.idea/misc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/cc-data.iml" filepath="$PROJECT_DIR$/.idea/cc-data.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
23
.vscode/launch.json
vendored
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
|
|
||||||
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
|
|
||||||
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"console": "integratedTerminal",
|
|
||||||
"internalConsoleOptions": "neverOpen",
|
|
||||||
"name": "NodeJS: nodemon debug",
|
|
||||||
"program": "${workspaceFolder}/backend/index.js",
|
|
||||||
"request": "launch",
|
|
||||||
// "restart": true,
|
|
||||||
"runtimeExecutable": "node",
|
|
||||||
// "runtimeExecutable": "nodemon",
|
|
||||||
"skipFiles": [
|
|
||||||
"<node_internals>/**"
|
|
||||||
],
|
|
||||||
"type": "node",
|
|
||||||
"envFile": "${workspaceFolder}/backend/.env",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
24
Dockerfile
@ -1,24 +0,0 @@
|
|||||||
FROM node:12
|
|
||||||
|
|
||||||
# Create app directory
|
|
||||||
RUN mkdir -p /usr/src/app
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
# Install app dependencies
|
|
||||||
# A wildcard is used to ensure both package.json AND package-lock.json are copied
|
|
||||||
# where available (npm@5+)
|
|
||||||
COPY backend/package*.json ./
|
|
||||||
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Bundle app source
|
|
||||||
COPY backend .
|
|
||||||
|
|
||||||
EXPOSE 3000
|
|
||||||
ENV PORT=3000
|
|
||||||
ENV METEOSTAT_API_KEY=LMlDskju
|
|
||||||
ENV DB_HOST=lhinderberger.dev
|
|
||||||
ENV DB_USER=root
|
|
||||||
ENV DB_PASSWORD=devtest
|
|
||||||
ENV DB_PORT=3306
|
|
||||||
CMD [ "node", "index.js" ]
|
|
||||||
40
README.md
@ -2,45 +2,9 @@
|
|||||||
|
|
||||||
Campus Cup AKMC Data Traveloptimizer
|
Campus Cup AKMC Data Traveloptimizer
|
||||||
|
|
||||||
## Backend
|
## Installation
|
||||||
|
|
||||||
### Requirements
|
|
||||||
- MariaDB or MySQL
|
|
||||||
- node `10.12` or higher
|
|
||||||
- Configure database in `.env`-file or environment variables. See `.env` for reference
|
|
||||||
- Set API-Key for meteostat.net in `.env`-file or environment variable
|
|
||||||
- import `setup.sql` for sample data
|
|
||||||
|
|
||||||
### Start
|
|
||||||
- Run `$(cd backend && npm run start)`
|
|
||||||
- call http://localhost:3000/v1/update/climate to fetch climate data for sample entries.
|
|
||||||
|
|
||||||
### Search
|
|
||||||
Customize your search with query parameters. For now, only climate parameters are supported. If you omit climate queries, all climate parameters will be randomized.
|
|
||||||
|
|
||||||
Following queries are supperted by now:
|
|
||||||
- from=YYYY-MM-DD _(required)_
|
|
||||||
- to=YYYY-MM-DD _(required)_
|
|
||||||
- temperature=NUMBER,NUMBER
|
|
||||||
- raindays=NUMBER,NUMBER
|
|
||||||
- sunhours=NUMBER,NUMBER
|
|
||||||
- precipitation=NUMBER,NUMBER
|
|
||||||
|
|
||||||
__Examples:__
|
|
||||||
http://localhost:3000/v1/search?from=2020-06-14&to=2020-07-29&temperature=27,29&raindays=8,12&sunhours=250,300
|
|
||||||
http://localhost:3000/v1/search?from=2020-06-14&to=2020-07-29
|
|
||||||
|
|
||||||
|
|
||||||
### More
|
|
||||||
To get more search results, add more entries with meteostat station IDs to the `regions` table in the database
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Frontend
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
- Install node 10.15.3
|
- Install node 10.15.3
|
||||||
- Run "(cd frontend && npm i)"
|
- Run "(cd frontend && npm i)"
|
||||||
|
|
||||||
### Start dev server
|
# Start dev server
|
||||||
- Run "(cd frontend && npm run start)"
|
- Run "(cd frontend && npm run start)"
|
||||||
|
|||||||
7070
Scripts/setup.sql
@ -1,10 +0,0 @@
|
|||||||
PORT=3000
|
|
||||||
METEOSTAT_API_KEY=LMlDskju
|
|
||||||
METEOSTAT_API_KEY_V2=O9X1xxKjheNwF1vfLcdRMmQ9JlobOugL
|
|
||||||
DB_HOST=lhinderberger.dev
|
|
||||||
DB_USER=root
|
|
||||||
DB_PASSWORD=devtest
|
|
||||||
DB_PORT=3306
|
|
||||||
DATABASE=travopti
|
|
||||||
GOOGLE_CLOUD_APIS=AIzaSyCeMBLfpqTp0IVB7Xipx6ekRQFUBjPacQc
|
|
||||||
SHOW_MATCH_VALUE=1
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
FROM node:12
|
|
||||||
|
|
||||||
# Create app directory
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
# COPY package.json .
|
|
||||||
# For npm@5 or later, copy package-lock.json as well
|
|
||||||
COPY package.json package-lock.json ./
|
|
||||||
|
|
||||||
# Install app dependencies
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Bundle app source
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
ENV PORT=3000
|
|
||||||
ENV METEOSTAT_API_KEY=LMlDskju
|
|
||||||
ENV DB_HOST=127.0.0.1
|
|
||||||
ENV DB_USER=root
|
|
||||||
ENV DB_PASSWORD=devtest
|
|
||||||
ENV DB_PORT=3306
|
|
||||||
ENV DATABASE=travopti
|
|
||||||
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
# Start Node server
|
|
||||||
CMD [ "node", "./index.js" ]
|
|
||||||
|
Before Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 253 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 221 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 270 KiB |
|
Before Width: | Height: | Size: 555 KiB |
|
Before Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 323 KiB |
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 393 KiB |
|
Before Width: | Height: | Size: 259 KiB |
|
Before Width: | Height: | Size: 304 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 370 KiB |
|
Before Width: | Height: | Size: 211 KiB |
|
Before Width: | Height: | Size: 308 KiB |
|
Before Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 198 KiB |
|
Before Width: | Height: | Size: 995 KiB |
|
Before Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 226 KiB |
|
Before Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 208 KiB |
|
Before Width: | Height: | Size: 276 KiB |
|
Before Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 487 KiB |
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 199 KiB |
|
Before Width: | Height: | Size: 374 KiB |
|
Before Width: | Height: | Size: 280 KiB |
|
Before Width: | Height: | Size: 398 KiB |
|
Before Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 213 KiB |
|
Before Width: | Height: | Size: 282 KiB |
|
Before Width: | Height: | Size: 267 KiB |
|
Before Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 287 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 216 KiB |
|
Before Width: | Height: | Size: 504 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
@ -1,94 +0,0 @@
|
|||||||
const express = require("express");
|
|
||||||
const bodyParser = require("body-parser");
|
|
||||||
const path = require("path");
|
|
||||||
const morgan = require("morgan");
|
|
||||||
const dbConnection = require("./util/dbConnection");
|
|
||||||
const fs = require("fs");
|
|
||||||
const cors = require("cors");
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
// credentials
|
|
||||||
const port = process.env.PORT
|
|
||||||
|
|
||||||
// Router
|
|
||||||
const search = require("./routes/search");
|
|
||||||
const regions = require("./routes/regions");
|
|
||||||
const countries = require("./routes/countries");
|
|
||||||
const places = require("./routes/place");
|
|
||||||
const update = require("./routes/update");
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
|
|
||||||
// Swagger API doc set up
|
|
||||||
const swaggerJsdoc = require('swagger-jsdoc');
|
|
||||||
const swaggerUi = require('swagger-ui-express');
|
|
||||||
const swaggerOptions = {
|
|
||||||
swaggerDefinition: {
|
|
||||||
openapi: "3.0.0",
|
|
||||||
info: {
|
|
||||||
title: "TravOpti API",
|
|
||||||
version: "1.0.0",
|
|
||||||
description:
|
|
||||||
"Enable intrest controlled region searching with this API\n" +
|
|
||||||
"No API Key required.",
|
|
||||||
license: {
|
|
||||||
name: "Licensing Pending",
|
|
||||||
url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be"
|
|
||||||
},
|
|
||||||
contact: {
|
|
||||||
name: "travOpti",
|
|
||||||
url: "https://travopti.de/home",
|
|
||||||
email: "feedback@travopti.de"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
servers: [
|
|
||||||
{
|
|
||||||
url: "https://travopti.de/api/v1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
apis: [
|
|
||||||
"./Routes/*.js",
|
|
||||||
"./Models/handleClimateUpdate.js",
|
|
||||||
"./Models/handleClimateUpdateV2.js",
|
|
||||||
]
|
|
||||||
};
|
|
||||||
const swaggerDocs = swaggerJsdoc(swaggerOptions);
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
// Connect to MariaDB
|
|
||||||
const dbConn = await dbConnection();
|
|
||||||
|
|
||||||
// Express middleware
|
|
||||||
app.use(morgan("dev"));
|
|
||||||
app.use(express.static(path.join(__dirname, "../../dist")));
|
|
||||||
app.use(bodyParser.json());
|
|
||||||
app.use(cors());
|
|
||||||
app.use('/api/v1/doc', swaggerUi.serve, swaggerUi.setup(swaggerDocs, {explorer: false, docExpansion: "list"}));
|
|
||||||
|
|
||||||
// Express routes
|
|
||||||
app.use(search(dbConn));
|
|
||||||
app.use(regions(dbConn));
|
|
||||||
app.use(countries(dbConn));
|
|
||||||
app.use(places(dbConn));
|
|
||||||
app.use(update(dbConn))
|
|
||||||
|
|
||||||
app.use((err, req, res, next) => {
|
|
||||||
// 500
|
|
||||||
if (true) {
|
|
||||||
next();
|
|
||||||
} else {
|
|
||||||
res.status(500).send();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Start webserver
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log(`Travopti backend listening at http://localhost:${port}`)
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to start the webserver");
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
module.exports = async (dbConn) => {
|
|
||||||
const countries = await dbConn.query(
|
|
||||||
`SELECT countries.id AS country_id,
|
|
||||||
countries.country AS name,
|
|
||||||
countries.description
|
|
||||||
FROM countries`
|
|
||||||
);
|
|
||||||
return countries;
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
module.exports = async (dbConn, id) => {
|
|
||||||
const country = await dbConn.query(
|
|
||||||
`SELECT countries.id AS country_id,
|
|
||||||
countries.country AS name,
|
|
||||||
countries.description
|
|
||||||
FROM countries
|
|
||||||
WHERE countries.id = ?`,
|
|
||||||
[id]
|
|
||||||
);
|
|
||||||
return country;
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
const axios = require("axios")
|
|
||||||
const getPlacePhoto = require("./getPlacePhoto.js")
|
|
||||||
|
|
||||||
const fields = "photos,place_id,name,rating,geometry" // Parameters for Google Place API
|
|
||||||
|
|
||||||
module.exports = async (q) => {
|
|
||||||
const res = await axios.get(
|
|
||||||
`https://maps.googleapis.com/maps/api/place/findplacefromtext/json?inputtype=textquery&fields=${fields}&input=${q}&key=${process.env.GOOGLE_CLOUD_APIS}`)
|
|
||||||
|
|
||||||
// Photo url is not returned by default since it overuses Google Place API
|
|
||||||
/*
|
|
||||||
for (let candidate of res.data.candidates) {
|
|
||||||
for (let photo of candidate.photos) {
|
|
||||||
photo.url = await getPlacePhoto(photo.photo_reference)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return res.data
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
const axios = require("axios")
|
|
||||||
const getPlacePhoto = require("./getPlacePhoto.js")
|
|
||||||
|
|
||||||
const radius = 20000 // Search radius in meters
|
|
||||||
const rankby = "prominence" // Sorting of results
|
|
||||||
const types = "tourist_attraction" // Category which shall be searched
|
|
||||||
|
|
||||||
module.exports = async (lat, lng) => {
|
|
||||||
const res = await axios.get(
|
|
||||||
`https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${lat},${lng}&radius=${radius}&type=${types}&rankby=${rankby}&key=${process.env.GOOGLE_CLOUD_APIS}`
|
|
||||||
);
|
|
||||||
// Photo url is not returned by default since it overuses Google Place API
|
|
||||||
/*
|
|
||||||
for (let result of res.data.results) {
|
|
||||||
for (let photo of result.photos) {
|
|
||||||
photo.url = await getPlacePhoto(photo.photo_reference)
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
return res.data
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
const axios = require("axios")
|
|
||||||
|
|
||||||
module.exports = async (photoref) => {
|
|
||||||
const res = await axios.get(
|
|
||||||
`https://maps.googleapis.com/maps/api/place/photo?photoreference=${photoref}&maxwidth=1600&key=${process.env.GOOGLE_CLOUD_APIS}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const url = res.request.res.responseUrl
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
const arrayFormatting = require("../util/databaseArrayFormatting.js")
|
|
||||||
|
|
||||||
module.exports = async (dbConn, id) => {
|
|
||||||
const res = await dbConn.query(
|
|
||||||
`SELECT regions.id AS region_id,
|
|
||||||
regions.region AS name,
|
|
||||||
countries.country AS country,
|
|
||||||
regions.description AS description,
|
|
||||||
regions.lon AS lon,
|
|
||||||
regions.lat AS lat,
|
|
||||||
rcma.temperature_mean AS temperature_mean,
|
|
||||||
rcma.temperature_mean_min AS temperature_mean_min,
|
|
||||||
rcma.temperature_mean_max AS temperature_mean_max,
|
|
||||||
rcma.precipitation AS precipitation,
|
|
||||||
rcma.rain_days AS rain_days,
|
|
||||||
rcma.sun_hours AS sun_hours,
|
|
||||||
rcma.humidity AS humidity,
|
|
||||||
regions_byt.average_per_day_costs AS average_per_day_costs,
|
|
||||||
rtma.avg_price_relative AS avg_price_relative,
|
|
||||||
regions_byt.accommodation_costs AS accommodation_costs,
|
|
||||||
regions_byt.food_costs AS food_costs,
|
|
||||||
regions_byt.water_costs AS water_costs,
|
|
||||||
regions_byt.local_transportation_costs AS local_transportation_costs,
|
|
||||||
regions_byt.entertainment_costs AS entertainment_costs,
|
|
||||||
regions_byt.alcohol_costs AS alcohol_costs
|
|
||||||
FROM regions
|
|
||||||
LEFT JOIN countries ON regions.country_id = countries.id
|
|
||||||
LEFT JOIN (SELECT rcma.region_id,
|
|
||||||
GROUP_CONCAT(rcma.temperature_mean ORDER BY rcma.month SEPARATOR ', ') AS temperature_mean,
|
|
||||||
GROUP_CONCAT(rcma.temperature_mean_min ORDER BY rcma.month SEPARATOR ', ') AS temperature_mean_min,
|
|
||||||
GROUP_CONCAT(rcma.temperature_mean_max ORDER BY rcma.month SEPARATOR ', ') AS temperature_mean_max,
|
|
||||||
GROUP_CONCAT(rcma.precipitation ORDER BY rcma.month SEPARATOR ', ') AS precipitation,
|
|
||||||
GROUP_CONCAT(rcma.rain_days ORDER BY rcma.month SEPARATOR ', ') AS rain_days,
|
|
||||||
GROUP_CONCAT(rcma.sun_hours ORDER BY rcma.month SEPARATOR ', ') AS sun_hours,
|
|
||||||
GROUP_CONCAT(rcma.humidity ORDER BY rcma.month SEPARATOR ', ') AS humidity
|
|
||||||
FROM region_climate_monthly_avg AS rcma
|
|
||||||
GROUP BY rcma.region_id) rcma ON rcma.region_id = regions.id
|
|
||||||
LEFT JOIN regions_byt ON regions.id = regions_byt.region_id
|
|
||||||
LEFT JOIN (SELECT rtma.region_id,
|
|
||||||
GROUP_CONCAT(rtma.avg_price_relative ORDER BY rtma.month SEPARATOR ', ') AS avg_price_relative
|
|
||||||
FROM regions_trivago_monthly_avg AS rtma
|
|
||||||
GROUP BY rtma.region_id) rtma
|
|
||||||
ON regions.id = rtma.region_id
|
|
||||||
WHERE regions_byt.travelstyle = 1
|
|
||||||
AND regions.id = ?`,
|
|
||||||
[id]
|
|
||||||
);
|
|
||||||
const region = res[0]
|
|
||||||
|
|
||||||
region.avg_price_relative = arrayFormatting(region.avg_price_relative);
|
|
||||||
region.temperature_mean = arrayFormatting(region.temperature_mean);
|
|
||||||
region.temperature_mean_min = arrayFormatting(region.temperature_mean_min);
|
|
||||||
region.temperature_mean_max = arrayFormatting(region.temperature_mean_max);
|
|
||||||
region.precipitation = arrayFormatting(region.precipitation);
|
|
||||||
region.rain_days = arrayFormatting(region.rain_days);
|
|
||||||
region.sun_hours = arrayFormatting(region.sun_hours);
|
|
||||||
region.humidity = arrayFormatting(region.humidity);
|
|
||||||
|
|
||||||
return region;
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
const arrayFormatting = require("../util/databaseArrayFormatting.js")
|
|
||||||
|
|
||||||
module.exports = async (dbConn, id) => {
|
|
||||||
const region_nearby = await dbConn.query(
|
|
||||||
`SELECT id as place_id,
|
|
||||||
region_id as region_id,
|
|
||||||
name as place_name,
|
|
||||||
lon as lon,
|
|
||||||
lat as lat,
|
|
||||||
rating as rating,
|
|
||||||
vicinity as vicinity,
|
|
||||||
photo_reference as photo_reference,
|
|
||||||
img_url as img_url
|
|
||||||
FROM regions_nearby
|
|
||||||
WHERE region_id = ?`,
|
|
||||||
[id]
|
|
||||||
);
|
|
||||||
|
|
||||||
return region_nearby;
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
const arrayFormatting = require("../util/databaseArrayFormatting.js");
|
|
||||||
const { allTagsWithValues } = require("./getTags.js");
|
|
||||||
|
|
||||||
module.exports = async (dbConn) => {
|
|
||||||
const sqlRegions = `SELECT regions.id AS region_id,
|
|
||||||
regions.region AS name,
|
|
||||||
countries.country AS country,
|
|
||||||
regions.description AS description,
|
|
||||||
regions.lon AS lon,
|
|
||||||
regions.lat AS lat,
|
|
||||||
rcma.temperature_mean AS temperature_mean,
|
|
||||||
rcma.temperature_mean_min AS temperature_mean_min,
|
|
||||||
rcma.temperature_mean_max AS temperature_mean_max,
|
|
||||||
rcma.precipitation AS precipitation,
|
|
||||||
rcma.rain_days AS rain_days,
|
|
||||||
rcma.sun_hours AS sun_hours,
|
|
||||||
rcma.humidity AS humidity,
|
|
||||||
regions_byt.average_per_day_costs AS average_per_day_costs,
|
|
||||||
rtma.avg_price_relative AS avg_price_relative,
|
|
||||||
regions_byt.accommodation_costs AS accommodation_costs,
|
|
||||||
regions_byt.food_costs AS food_costs,
|
|
||||||
regions_byt.water_costs AS water_costs,
|
|
||||||
regions_byt.local_transportation_costs AS local_transportation_costs,
|
|
||||||
regions_byt.entertainment_costs AS entertainment_costs,
|
|
||||||
regions_byt.alcohol_costs AS alcohol_costs
|
|
||||||
FROM regions
|
|
||||||
LEFT JOIN countries ON regions.country_id = countries.id
|
|
||||||
LEFT JOIN (SELECT rcma.region_id,
|
|
||||||
GROUP_CONCAT(rcma.temperature_mean ORDER BY rcma.month SEPARATOR ', ') AS temperature_mean,
|
|
||||||
GROUP_CONCAT(rcma.temperature_mean_min ORDER BY rcma.month SEPARATOR ', ') AS temperature_mean_min,
|
|
||||||
GROUP_CONCAT(rcma.temperature_mean_max ORDER BY rcma.month SEPARATOR ', ') AS temperature_mean_max,
|
|
||||||
GROUP_CONCAT(rcma.precipitation ORDER BY rcma.month SEPARATOR ', ') AS precipitation,
|
|
||||||
GROUP_CONCAT(rcma.rain_days ORDER BY rcma.month SEPARATOR ', ') AS rain_days,
|
|
||||||
GROUP_CONCAT(rcma.sun_hours ORDER BY rcma.month SEPARATOR ', ') AS sun_hours,
|
|
||||||
GROUP_CONCAT(rcma.humidity ORDER BY rcma.month SEPARATOR ', ') AS humidity
|
|
||||||
FROM region_climate_monthly_avg AS rcma
|
|
||||||
GROUP BY rcma.region_id) rcma ON rcma.region_id = regions.id
|
|
||||||
LEFT JOIN regions_byt ON regions.id = regions_byt.region_id
|
|
||||||
LEFT JOIN (SELECT rtma.region_id,
|
|
||||||
GROUP_CONCAT(rtma.avg_price_relative ORDER BY rtma.month SEPARATOR ', ') AS avg_price_relative
|
|
||||||
FROM regions_trivago_monthly_avg AS rtma
|
|
||||||
GROUP BY rtma.region_id) rtma
|
|
||||||
ON regions.id = rtma.region_id
|
|
||||||
WHERE regions_byt.travelstyle = 1`
|
|
||||||
|
|
||||||
const [regions, tags] = await Promise.all([dbConn.query(sqlRegions), allTagsWithValues(dbConn)])
|
|
||||||
|
|
||||||
for (k = 0; k < regions.length; k++) {
|
|
||||||
regions[k].avg_price_relative = arrayFormatting(regions[k].avg_price_relative);
|
|
||||||
regions[k].temperature_mean = arrayFormatting(regions[k].temperature_mean);
|
|
||||||
regions[k].temperature_mean_min = arrayFormatting(regions[k].temperature_mean_min);
|
|
||||||
regions[k].temperature_mean_max = arrayFormatting(regions[k].temperature_mean_max);
|
|
||||||
regions[k].precipitation = arrayFormatting(regions[k].precipitation);
|
|
||||||
regions[k].rain_days = arrayFormatting(regions[k].rain_days);
|
|
||||||
regions[k].sun_hours = arrayFormatting(regions[k].sun_hours);
|
|
||||||
regions[k].humidity = arrayFormatting(regions[k].humidity);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return regions.map(region => {
|
|
||||||
region.tags = tags.filter(tag => tag.region_id === region.region_id).map(tag => {
|
|
||||||
delete tag.region_id
|
|
||||||
return tag
|
|
||||||
})
|
|
||||||
|
|
||||||
return region
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
module.exports = async (dbConn) => {
|
|
||||||
let presets = await dbConn.query(
|
|
||||||
`SELECT search_presets.id AS preset_id,
|
|
||||||
search_presets.parameter AS parameter,
|
|
||||||
search_presets.name AS tag_label,
|
|
||||||
CASE
|
|
||||||
WHEN value_2 is NULL THEN value_1
|
|
||||||
ELSE CONCAT(search_presets.value_1,"|",search_presets.value_2)
|
|
||||||
END AS "value"
|
|
||||||
FROM search_presets`
|
|
||||||
);
|
|
||||||
|
|
||||||
for (k = 0; k < presets.length; k++) {
|
|
||||||
const value = presets[k].value
|
|
||||||
presets[k].value = value.split("|");
|
|
||||||
for (i = 0; i < presets[k].value.length; i++) {
|
|
||||||
presets[k].value[i] = parseFloat(presets[k].value[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return presets;
|
|
||||||
};
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
exports.getUniqueTags = async (dbConn) => {
|
|
||||||
let tags = await dbConn.query(
|
|
||||||
`SELECT DISTINCT name FROM region_feedback;`
|
|
||||||
);
|
|
||||||
return tags;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.allTagsWithValues = async (dbConn) => {
|
|
||||||
let tags = await dbConn.query(
|
|
||||||
`SELECT region_id, name, value FROM region_feedback;`
|
|
||||||
);
|
|
||||||
return tags;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.getTagsByRegionId = async (dbConn, id) => {
|
|
||||||
let tags = await dbConn.query(
|
|
||||||
`SELECT region_id, name, value
|
|
||||||
FROM region_feedback
|
|
||||||
WHERE region_id = ${id};`
|
|
||||||
);
|
|
||||||
return tags;
|
|
||||||
};
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
const axios = require('axios')
|
|
||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
// TODO: Automatically retrieve dates via aviable Data from database and get rid of "random" dates
|
|
||||||
const rangeStartDate = '2019-01' // If no date is given, this date will be used as startDate
|
|
||||||
const rangeEndDate = '2020-05'// If no date is given, this date will be used as endDate
|
|
||||||
|
|
||||||
// TODO: call method periodically, not over API (fine for prototyping, tho)
|
|
||||||
module.exports = async (dbConn, startDate = rangeStartDate, endDate = rangeEndDate) => {
|
|
||||||
console.log('update climate with:', startDate, endDate);
|
|
||||||
|
|
||||||
const result = await dbConn.query(`SELECT * FROM regions WHERE meteostat_id IS NOT NULL`)
|
|
||||||
|
|
||||||
const climateObject = await Promise.all(result.map(src => {
|
|
||||||
return createClimateObjectFrom(src, startDate, endDate)
|
|
||||||
}))
|
|
||||||
const climateObjectArr = climateObject.reduce((total, element) => total.concat(element), [])
|
|
||||||
|
|
||||||
await writeToDatabase(dbConn, climateObjectArr)
|
|
||||||
|
|
||||||
const res = `region_climate update complete. see backend logs for info.`
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createClimateObjectFrom(src, startDate, endDate) {
|
|
||||||
let res
|
|
||||||
if (src.meteostat_id === '') {
|
|
||||||
console.log("skipping: no meteostat id ")
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
res = await axios.get(`https://api.meteostat.net/v1/history/monthly?station=${src.meteostat_id}&start=${startDate}&end=${endDate}&key=${process.env.METEOSTAT_API_KEY}`)
|
|
||||||
} catch (error) {
|
|
||||||
console.log("error while getting data from meteostat: couldn't find results for following region: ")
|
|
||||||
console.log(src.region + " with meteostat_id " + src.meteostat_id)
|
|
||||||
console.log(error)
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
if (!res.data.data) {
|
|
||||||
console.log("skipping: no data for station with meteostat_id " + src.meteostat_id + " (" + src.region + ")")
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
const retVal = res.data.data.map(element => {
|
|
||||||
let result = {
|
|
||||||
region: src.region,
|
|
||||||
region_id: src.id,
|
|
||||||
year: element.month.split("-")[0],
|
|
||||||
month: element.month.split("-")[1],
|
|
||||||
temperature_mean: element.temperature_mean,
|
|
||||||
temperature_mean_min: element.temperature_mean_min,
|
|
||||||
temperature_mean_max: element.temperature_mean_max,
|
|
||||||
precipitation: element.precipitation,
|
|
||||||
rain_days: element.raindays,
|
|
||||||
sun_hours: element.sunshine,
|
|
||||||
humidity: element.humidity ? element.humidity : null
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
return retVal
|
|
||||||
}
|
|
||||||
|
|
||||||
async function writeToDatabase(dbConn, climateObjArr) {
|
|
||||||
for (const element of climateObjArr) {
|
|
||||||
try {
|
|
||||||
await dbConn.query(`
|
|
||||||
INSERT INTO region_climate
|
|
||||||
(region_id, year, month, temperature_mean, temperature_mean_min, temperature_mean_max, precipitation, sun_hours, humidity, rain_days)
|
|
||||||
VALUES (${element.region_id}, ${element.year}, ${element.month}, ${element.temperature_mean}, ${element.temperature_mean_min}, ${element.temperature_mean_max}, ${element.precipitation}, ${element.sun_hours}, ${element.humidity}, ${element.rain_days})
|
|
||||||
ON DUPLICATE KEY UPDATE
|
|
||||||
temperature_mean = ${element.temperature_mean},
|
|
||||||
temperature_mean_min = ${element.temperature_mean_min},
|
|
||||||
temperature_mean_max = ${element.temperature_mean_max},
|
|
||||||
precipitation = ${element.precipitation},
|
|
||||||
sun_hours = ${element.sun_hours},
|
|
||||||
humidity = ${element.humidity},
|
|
||||||
rain_days = ${element.rain_days};`)
|
|
||||||
} catch (error) {
|
|
||||||
if (error.code !== 'ER_DUP_ENTRY') {
|
|
||||||
console.log("element which causes problems: ")
|
|
||||||
console.log(element)
|
|
||||||
console.log("query which causes problems: ")
|
|
||||||
console.log(error)
|
|
||||||
} else {
|
|
||||||
console.log(element.region + ": " + error.sqlMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,110 +0,0 @@
|
|||||||
const axios = require('axios')
|
|
||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
// TODO: Automatically retrieve dates via aviable Data from database and get rid of "random" dates
|
|
||||||
const rangeStartDate = '2019-01-01' // If no date is given, this date will be used as startDate
|
|
||||||
const rangeEndDate = '2019-12-31'// If no date is given, this date will be used as endDate
|
|
||||||
|
|
||||||
// TODO: call method periodically, not over API (fine for prototyping, tho)
|
|
||||||
module.exports = async (dbConn, startDate = rangeStartDate, endDate = rangeEndDate) => {
|
|
||||||
console.log('update climate with:', startDate, endDate);
|
|
||||||
|
|
||||||
const result = await dbConn.query(`SELECT id, region, lon, lat FROM regions`)
|
|
||||||
|
|
||||||
const climateObject = await Promise.all(result.map(src => {
|
|
||||||
return createClimateObjectFrom(src, startDate, endDate)
|
|
||||||
}))
|
|
||||||
const climateObjectArr = climateObject.reduce((total, element) => total.concat(element), [])
|
|
||||||
|
|
||||||
await writeToDatabase(dbConn, climateObjectArr)
|
|
||||||
|
|
||||||
const res = `region_climate update v2 complete. see backend logs for info.`
|
|
||||||
return climateObjectArr
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createClimateObjectFrom(src, startDate, endDate) {
|
|
||||||
let res
|
|
||||||
try {
|
|
||||||
res = await axios.get(
|
|
||||||
`https://api.meteostat.net/v2/point/daily?lat=${src.lat}&lon=${src.lon}&start=${startDate}&end=${endDate}`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"x-api-key": process.env.METEOSTAT_API_KEY_V2
|
|
||||||
}//,
|
|
||||||
//httpsAgent: agent
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.log("error while getting data from meteostat: couldn't find results for following region: ")
|
|
||||||
console.log(src.region,"with coords:",src.lon,src.lat)
|
|
||||||
console.log(error)
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
if (!res.data.data) {
|
|
||||||
console.log("skipping: no data for station with meteostat_id " + src.meteostat_id + " (" + src.region + ")")
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
const retVal = res.data.data.map(element => {
|
|
||||||
let result = {
|
|
||||||
region: src.region,
|
|
||||||
region_id: src.id,
|
|
||||||
year: element.date.split("-")[0],
|
|
||||||
month: element.date.split("-")[1],
|
|
||||||
day: element.date.split("-")[2],
|
|
||||||
temperature_mean: element.tavg,
|
|
||||||
temperature_mean_min: element.tmin,
|
|
||||||
temperature_mean_max: element.tmax,
|
|
||||||
precipitation: element.prcp,
|
|
||||||
rain_days: element.prcp > 2 ? 1:0, // More than 2mm => rainday
|
|
||||||
sun_hours: element.tsun/60
|
|
||||||
}
|
|
||||||
//console.log(result)
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
return retVal
|
|
||||||
}
|
|
||||||
|
|
||||||
async function writeToDatabase(dbConn, climateObjArr) {
|
|
||||||
for (const element of climateObjArr) {
|
|
||||||
//console.log(element)
|
|
||||||
try {
|
|
||||||
await dbConn.query(`
|
|
||||||
INSERT INTO region_climate_day
|
|
||||||
(region_id, year, month, day, temperature_mean, temperature_mean_min, temperature_mean_max, precipitation, sun_hours, rain_days)
|
|
||||||
VALUES (${element.region_id}, ${element.year}, ${element.month}, ${element.day}, ${element.temperature_mean}, ${element.temperature_mean_min}, ${element.temperature_mean_max}, ${element.precipitation}, ${element.sun_hours}, ${element.rain_days})
|
|
||||||
ON DUPLICATE KEY UPDATE
|
|
||||||
temperature_mean = ${element.temperature_mean},
|
|
||||||
temperature_mean_min = ${element.temperature_mean_min},
|
|
||||||
temperature_mean_max = ${element.temperature_mean_max},
|
|
||||||
precipitation = ${element.precipitation},
|
|
||||||
sun_hours = ${element.sun_hours},
|
|
||||||
rain_days = ${element.rain_days};`)
|
|
||||||
} catch (error) {
|
|
||||||
if (error.code !== 'ER_DUP_ENTRY') {
|
|
||||||
console.log("element which causes problems: ")
|
|
||||||
console.log(element)
|
|
||||||
console.log("query which causes problems: ")
|
|
||||||
console.log(error)
|
|
||||||
} else {
|
|
||||||
console.log(element.region + ": " + error.sqlMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
INSERT INTO region_climate
|
|
||||||
(region_id, YEAR, MONTH, temperature_mean, temperature_mean_min, temperature_mean_max, precipitation, rain_days, sun_hours)
|
|
||||||
SELECT
|
|
||||||
region_id,
|
|
||||||
YEAR,
|
|
||||||
MONTH,
|
|
||||||
ROUND(AVG(temperature_mean),2) AS temperature_mean,
|
|
||||||
MIN(temperature_mean_min) AS temperature_mean_min,
|
|
||||||
MAX(temperature_mean_max) AS temperature_mean_max,
|
|
||||||
ROUND(SUM(precipitation),2) AS precipitation,
|
|
||||||
SUM(rain_days) AS rain_days,
|
|
||||||
SUM(sun_hours) AS sun_hours
|
|
||||||
FROM region_climate_day
|
|
||||||
GROUP BY region_id, YEAR, month
|
|
||||||
*/
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
const axios = require("axios")
|
|
||||||
const getRegions = require("../models/getRegions.js")
|
|
||||||
|
|
||||||
const fields = "geometry" // Parameters for Google Places API
|
|
||||||
|
|
||||||
module.exports = async (dbConn) => {
|
|
||||||
const regions = await getRegions(dbConn)
|
|
||||||
|
|
||||||
for (let region of regions) {
|
|
||||||
try {
|
|
||||||
const q = region.name
|
|
||||||
|
|
||||||
const place = await axios.get(
|
|
||||||
`https://maps.googleapis.com/maps/api/place/findplacefromtext/json?inputtype=textquery&fields=geometry&input=${q}&key=${process.env.GOOGLE_CLOUD_APIS}`)
|
|
||||||
|
|
||||||
const region_id = region.region_id
|
|
||||||
const lon = parseFloat(place.data.candidates[0].geometry.location.lng)
|
|
||||||
const lat = parseFloat(place.data.candidates[0].geometry.location.lat)
|
|
||||||
|
|
||||||
await dbConn.query(
|
|
||||||
`UPDATE regions
|
|
||||||
SET lon=${lon}, lat=${lat}
|
|
||||||
WHERE id = ${region_id}`
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log("Updating coordinates for region: ", region_id, q, " ", "lon:", lon, "lat", lat)
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = "lon lat update finished"
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
const axios = require("axios")
|
|
||||||
const getRegions = require("../models/getRegions.js")
|
|
||||||
const getPlaceNearby = require("../models/getPlaceNearby.js")
|
|
||||||
|
|
||||||
module.exports = async (dbConn) => {
|
|
||||||
const regions = await getRegions(dbConn)
|
|
||||||
|
|
||||||
for (let region of regions) {
|
|
||||||
try {
|
|
||||||
const region_id = region.region_id
|
|
||||||
const region_lon = region.lon
|
|
||||||
const region_lat = region.lat
|
|
||||||
|
|
||||||
console.log("Updating nearby for region: ", region_id, region.name)
|
|
||||||
|
|
||||||
const places = await getPlaceNearby(region_lat, region_lon)
|
|
||||||
|
|
||||||
for (let result of places.results) {
|
|
||||||
const name = result.name
|
|
||||||
const rating = result.rating === undefined ? null : result.rating
|
|
||||||
const lon = result.geometry.location.lng
|
|
||||||
const lat = result.geometry.location.lat
|
|
||||||
const photo_ref = result.photos[0].photo_reference
|
|
||||||
const vicinity = result.vicinity
|
|
||||||
|
|
||||||
console.log("# New tourist attraction:", region_id, region.name, name)
|
|
||||||
|
|
||||||
await dbConn.query(
|
|
||||||
`INSERT INTO regions_nearby
|
|
||||||
(region_id,name,lon,lat,rating,vicinity,photo_reference)
|
|
||||||
VALUES
|
|
||||||
(${region_id},"${name}",${lon},${lat},${rating},"${vicinity}","${photo_ref}")
|
|
||||||
ON DUPLICATE KEY UPDATE
|
|
||||||
lon = ${lon},
|
|
||||||
lat = ${lat},
|
|
||||||
rating = ${rating},
|
|
||||||
vicinity = "${vicinity}",
|
|
||||||
photo_reference = "${photo_ref}"`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = "region nearby update finished"
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
const axios = require("axios")
|
|
||||||
const getRegionById = require("../models/getRegionById.js")
|
|
||||||
const getPlaceNearby = require("../models/getPlaceNearby.js")
|
|
||||||
|
|
||||||
module.exports = async (dbConn, id) => {
|
|
||||||
const region = await getRegionById(dbConn, id)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const region_id = region.region_id
|
|
||||||
const region_lon = region.lon
|
|
||||||
const region_lat = region.lat
|
|
||||||
|
|
||||||
console.log("Updating nearby for region: ", region_id, region.name)
|
|
||||||
|
|
||||||
const places = await getPlaceNearby(region_lat, region_lon)
|
|
||||||
|
|
||||||
for (let result of places.results) {
|
|
||||||
try {
|
|
||||||
const name = result.name
|
|
||||||
const rating = result.rating === undefined ? null : result.rating
|
|
||||||
const lon = result.geometry.location.lng
|
|
||||||
const lat = result.geometry.location.lat
|
|
||||||
const photo_ref = result.photos[0].photo_reference
|
|
||||||
const vicinity = result.vicinity
|
|
||||||
|
|
||||||
console.log("# New tourist attraction:", region_id, region.name, name)
|
|
||||||
|
|
||||||
await dbConn.query(
|
|
||||||
`INSERT INTO regions_nearby
|
|
||||||
(region_id,name,lon,lat,rating,vicinity,photo_reference)
|
|
||||||
VALUES
|
|
||||||
(${region_id},"${name}",${lon},${lat},${rating},"${vicinity}","${photo_ref}")
|
|
||||||
ON DUPLICATE KEY UPDATE
|
|
||||||
lon = ${lon},
|
|
||||||
lat = ${lat},
|
|
||||||
rating = ${rating},
|
|
||||||
vicinity = "${vicinity}",
|
|
||||||
photo_reference = "${photo_ref}"`
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const res = "region nearby by id update finished"
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
const getRegionNearbyById = require("../models/getRegionNearbyById.js")
|
|
||||||
const getPlacePhoto = require("../models/getPlacePhoto.js")
|
|
||||||
|
|
||||||
module.exports = async (dbConn) => {
|
|
||||||
try {
|
|
||||||
const region_ids = await dbConn.query(`
|
|
||||||
SELECT distinct region_id
|
|
||||||
FROM regions_nearby
|
|
||||||
ORDER BY region_id`)
|
|
||||||
|
|
||||||
|
|
||||||
for (let region_id of region_ids) {
|
|
||||||
const nearby = await getRegionNearbyById(dbConn, region_id.region_id)
|
|
||||||
|
|
||||||
for (let place of nearby) {
|
|
||||||
const url = await getPlacePhoto(place.photo_reference)
|
|
||||||
|
|
||||||
console.log("# Setting image Url:", region_id, place.place_name, url)
|
|
||||||
|
|
||||||
await dbConn.query(`
|
|
||||||
UPDATE regions_nearby
|
|
||||||
SET img_url = "${url}"
|
|
||||||
WHERE id = ${place.place_id}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = "region nearby img url update finished"
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
const getRegionNearbyById = require("../models/getRegionNearbyById.js")
|
|
||||||
const getPlacePhoto = require("../models/getPlacePhoto.js")
|
|
||||||
|
|
||||||
module.exports = async (dbConn,id) => {
|
|
||||||
try {
|
|
||||||
const region_ids = await dbConn.query(`
|
|
||||||
SELECT distinct region_id
|
|
||||||
FROM regions_nearby
|
|
||||||
WHERE region_id = ?`,
|
|
||||||
[id])
|
|
||||||
|
|
||||||
|
|
||||||
for (let region_id of region_ids) {
|
|
||||||
const nearby = await getRegionNearbyById(dbConn, region_id.region_id)
|
|
||||||
|
|
||||||
for (let place of nearby) {
|
|
||||||
const url = await getPlacePhoto(place.photo_reference)
|
|
||||||
|
|
||||||
console.log("# Setting image Url:", region_id, place.place_name, url)
|
|
||||||
|
|
||||||
await dbConn.query(`
|
|
||||||
UPDATE regions_nearby
|
|
||||||
SET img_url = "${url}"
|
|
||||||
WHERE id = ${place.place_id}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = "region nearby img url update finished"
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
1833
backend/package-lock.json
generated
@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "cc-data-backend",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"start": "nodemon ./index.js"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"axios": "^0.19.2",
|
|
||||||
"body-parser": "^1.19.0",
|
|
||||||
"cors": "^2.8.5",
|
|
||||||
"dotenv": "^8.2.0",
|
|
||||||
"express": "^4.17.1",
|
|
||||||
"httpolyglot": "^0.1.2",
|
|
||||||
"lodash": "^4.17.15",
|
|
||||||
"mariadb": "^2.4.0",
|
|
||||||
"moment": "^2.26.0",
|
|
||||||
"morgan": "^1.10.0",
|
|
||||||
"mysql2": "^2.1.0",
|
|
||||||
"path": "^0.12.7",
|
|
||||||
"sqlstring": "^2.3.2",
|
|
||||||
"swagger-jsdoc": "^4.0.0",
|
|
||||||
"swagger-ui-express": "^4.1.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"nodemon": "^2.0.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* tags:
|
|
||||||
* name: Countries
|
|
||||||
* description: Access country data.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const router = require("express").Router();
|
|
||||||
|
|
||||||
// Models
|
|
||||||
const getCountries = require("../models/getCountries.js");
|
|
||||||
const getCountryById = require("../models/getCountryById.js");
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
const sqlSanitzer = require("../util/sqlstring_sanitizer.js")
|
|
||||||
|
|
||||||
module.exports = dbConn => {
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /countries:
|
|
||||||
* get:
|
|
||||||
* summary: Get all countries
|
|
||||||
* tags: [Countries]
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns aviable data for all countries
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/countries", async (req, res) => {
|
|
||||||
res.json(await getCountries(dbConn));
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /countries/{id}:
|
|
||||||
* get:
|
|
||||||
* summary: Get a specific country by id
|
|
||||||
* tags: [Countries]
|
|
||||||
* parameters:
|
|
||||||
* - name: "id"
|
|
||||||
* in: "path"
|
|
||||||
* required: true
|
|
||||||
* type: int
|
|
||||||
* example: 23
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns aviable data for the country
|
|
||||||
* example: test
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/countries/:id", async (req, res) => {
|
|
||||||
const id = sqlSanitzer(req.params.id);
|
|
||||||
res.json(await getCountryById(dbConn, id))
|
|
||||||
});
|
|
||||||
return router;
|
|
||||||
};
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* tags:
|
|
||||||
* name: Places
|
|
||||||
* description: Access to the Google Place API via the Key used in backend. Only for manual use in the prototype application!
|
|
||||||
*/
|
|
||||||
|
|
||||||
const router = require("express").Router()
|
|
||||||
|
|
||||||
// Models
|
|
||||||
const getPlace = require("../models/getPlace.js")
|
|
||||||
const getPlaceNearby = require("../models/getPlaceNearby.js")
|
|
||||||
const getPlacePhoto = require("../models/getPlacePhoto.js")
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
const sqlSanitzer = require("../util/sqlstring_sanitizer.js")
|
|
||||||
|
|
||||||
module.exports = dbConn => {
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /place:
|
|
||||||
* get:
|
|
||||||
* summary: Get a specific place
|
|
||||||
* tags: [Places]
|
|
||||||
* parameters:
|
|
||||||
* - name: "q"
|
|
||||||
* in: "query"
|
|
||||||
* required: true
|
|
||||||
* type: int
|
|
||||||
* description: "Querystring, by which the place is searched"
|
|
||||||
* example: Berlin
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns a place from the google places API.
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/place", async (req, res) => {
|
|
||||||
const place = await getPlace(req.query.q)
|
|
||||||
res.json(place)
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /place/nearby:
|
|
||||||
* get:
|
|
||||||
* summary: Get nearby touristic places
|
|
||||||
* tags: [Places]
|
|
||||||
* parameters:
|
|
||||||
* - name: "lat"
|
|
||||||
* in: "query"
|
|
||||||
* required: true
|
|
||||||
* type: float
|
|
||||||
* description: "Latitiude"
|
|
||||||
* example: 52.520365
|
|
||||||
* - name: "lng"
|
|
||||||
* in: "query"
|
|
||||||
* required: true
|
|
||||||
* type: float
|
|
||||||
* description: "Longitude"
|
|
||||||
* example: 13.403509
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns nearby places from the google places API.
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/place/nearby", async (req, res) => {
|
|
||||||
const lat = req.query.lat
|
|
||||||
const lng = req.query.lng
|
|
||||||
const place = await getPlaceNearby(lat, lng)
|
|
||||||
res.json(place)
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /place/photo:
|
|
||||||
* get:
|
|
||||||
* summary: Get a photo for a place
|
|
||||||
* tags: [Places]
|
|
||||||
* parameters:
|
|
||||||
* - name: "photoref"
|
|
||||||
* in: "query"
|
|
||||||
* required: true
|
|
||||||
* type: int
|
|
||||||
* description: "Photo_Reference which is returned for a place by Google Places API"
|
|
||||||
* example: CmRaAAAAbupojmH94negtiCnLGdfx2azxhVTEDI1rtTrYnQ7KclEI-Yy9_YGxN9h63AKrCzd22kk5z-UiK7fS4-zXnO5OqfNRZu2hrmfcp8b77rItediibAVovOOA5LnyJ9YYuofEhAAr0Im0zuiAtbDKPjbPUSBGhTFkSrH6FZxenbo1bCkdCXaUMhOug
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns the matching url to the photo.
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/place/photo", async (req, res) => {
|
|
||||||
const photoref = req.query.photoref
|
|
||||||
const photo = await getPlacePhoto(photoref)
|
|
||||||
res.json(photo)
|
|
||||||
});
|
|
||||||
|
|
||||||
return router;
|
|
||||||
};
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* tags:
|
|
||||||
* name: Regions
|
|
||||||
* description: Access region data.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const router = require("express").Router();
|
|
||||||
|
|
||||||
// Models
|
|
||||||
const getRegions = require("../models/getRegions.js");
|
|
||||||
const getRegionById = require("../models/getRegionById.js");
|
|
||||||
const getRegionNearbyById = require("../models/getRegionNearbyById.js")
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
const path = require("path");
|
|
||||||
const fs = require("fs");
|
|
||||||
const _ = require('lodash')
|
|
||||||
const sqlSanitzer = require("../util/sqlstring_sanitizer.js")
|
|
||||||
|
|
||||||
module.exports = dbConn => {
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /regions:
|
|
||||||
* get:
|
|
||||||
* summary: Get all regions
|
|
||||||
* tags: [Regions]
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns available data for all regions
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/regions", async (req, res) => {
|
|
||||||
const data = await getRegions(dbConn)
|
|
||||||
if (req.query.randomize) {
|
|
||||||
const randomize = sqlSanitzer(req.query.randomize)
|
|
||||||
res.json(_.sampleSize(data, randomize))
|
|
||||||
} else {
|
|
||||||
res.json(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /regions/{id}:
|
|
||||||
* get:
|
|
||||||
* summary: Get a specific region by id
|
|
||||||
* tags: [Regions]
|
|
||||||
* parameters:
|
|
||||||
* - name: "id"
|
|
||||||
* in: "path"
|
|
||||||
* required: true
|
|
||||||
* type: int
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns available data for the region
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/regions/:id", async (req, res) => {
|
|
||||||
console.log(typeof req.params.id)
|
|
||||||
const id = sqlSanitzer(req.params.id);
|
|
||||||
console.log(id)
|
|
||||||
res.json(await getRegionById(dbConn, id))
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /regions/{id}/image:
|
|
||||||
* get:
|
|
||||||
* summary: Get image for specific region
|
|
||||||
* tags: [Regions]
|
|
||||||
* parameters:
|
|
||||||
* - name: "id"
|
|
||||||
* in: "path"
|
|
||||||
* required: true
|
|
||||||
* type: int
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns the image for a specific region
|
|
||||||
* "404":
|
|
||||||
* description: Returns a placeholder image for the region
|
|
||||||
*/
|
|
||||||
router.get('/api/v1/regions/:id/image', (req, res) => {
|
|
||||||
console.log("HERE")
|
|
||||||
if (fs.existsSync(path.join(__dirname, `../data/regions/images/${req.params.id}.jpg`))) {
|
|
||||||
console.log("EXISTS")
|
|
||||||
res.status(200).sendFile(path.join(__dirname, `../data/regions/images/${req.params.id}.jpg`))
|
|
||||||
} else {
|
|
||||||
console.log("NOT EXISTS")
|
|
||||||
res.status(404).sendFile(path.join(__dirname, `../data/regions/images/x.png`))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /regions/{id}/nearby:
|
|
||||||
* get:
|
|
||||||
* summary: Get nearby places of a specific region by id
|
|
||||||
* tags: [Regions]
|
|
||||||
* parameters:
|
|
||||||
* - name: "id"
|
|
||||||
* in: "path"
|
|
||||||
* required: true
|
|
||||||
* type: int
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns all nearby places for the region
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/regions/:id/nearby", async (req,res) => {
|
|
||||||
const id = sqlSanitzer(req.params.id);
|
|
||||||
res.json(await getRegionNearbyById(dbConn,id))
|
|
||||||
});
|
|
||||||
return router;
|
|
||||||
};
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* tags:
|
|
||||||
* name: Search
|
|
||||||
* description: Access the search algorithm and the data provided for searching.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const router = require("express").Router();
|
|
||||||
|
|
||||||
// Models
|
|
||||||
const getRegions = require('../models/getRegions.js');
|
|
||||||
const getSearchPresets = require("../models/getSearchPresets.js");
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
const _ = require('lodash')
|
|
||||||
const base64 = require("../util/base64.js")
|
|
||||||
const scoreAndSearch = require("../util/scoreAndSearch.js");
|
|
||||||
const oldToNewQuerySyntax = require("../util/oldToNewQuerySyntax.js")
|
|
||||||
const { getUniqueTags } = require("../models/getTags.js");
|
|
||||||
|
|
||||||
module.exports = dbConn => {
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /search:
|
|
||||||
* get:
|
|
||||||
* summary: Get Searchresults
|
|
||||||
* tags: [Search]
|
|
||||||
* parameters:
|
|
||||||
* - name: "q"
|
|
||||||
* in: "query"
|
|
||||||
* required: true
|
|
||||||
* type: int
|
|
||||||
* description: "Base64 encoded JS-Object with searchparameters"
|
|
||||||
* example: eyJmcm9tIjoxNTkzNjQ4MDAwMDAwLCJ0byI6MTU5NDI1MjgwMDAwMCwidGFncyI6W119
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns the region information and scores for the searchresults
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/search", searchHandler(dbConn));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /search/presets:
|
|
||||||
* get:
|
|
||||||
* summary: Get the presets for the search parameters
|
|
||||||
* tags: [Search]
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns all presets for the search parameters
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/search/presets", presetHandler(dbConn));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /search/tags:
|
|
||||||
* get:
|
|
||||||
* summary: Get the existing searchtags
|
|
||||||
* tags: [Search]
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Returns all existing searchtags
|
|
||||||
*/
|
|
||||||
router.get("/api/v1/search/tags", tagsHandler(dbConn));
|
|
||||||
|
|
||||||
return router;
|
|
||||||
};
|
|
||||||
|
|
||||||
function tagsHandler(dbConn) {
|
|
||||||
return function (req, res) {
|
|
||||||
getUniqueTags(dbConn).then(tags => {
|
|
||||||
res.json(tags.map(tag => tag.name))
|
|
||||||
}).catch(error => {
|
|
||||||
// TODO error handling
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function presetHandler(dbConn) {
|
|
||||||
return function (req, res) {
|
|
||||||
getSearchPresets(dbConn).then(presets => {
|
|
||||||
res.json(presets)
|
|
||||||
}).catch(error => {
|
|
||||||
// TODO error handling
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchHandler(dbConn) {
|
|
||||||
return async function (req, res) {
|
|
||||||
let response = {}
|
|
||||||
|
|
||||||
response.meta = {
|
|
||||||
params: req.params,
|
|
||||||
query: req.query,
|
|
||||||
headers: req.headers
|
|
||||||
}
|
|
||||||
|
|
||||||
// SWITCH TO SUPPORT OLD AND NEW BASE64 BASED QUERY SYNTAX
|
|
||||||
let q = req.query.q ? base64.base64ToObj(req.query.q) : req.query
|
|
||||||
console.log('Q:', q)
|
|
||||||
|
|
||||||
// transform syntax and seperate climate queries from price queries
|
|
||||||
if (!req.query.q) {
|
|
||||||
q = oldToNewQuerySyntax(q)
|
|
||||||
}
|
|
||||||
// CHOOSE PARAMS WHICH SHALL BE PASSED TO SCORE AND SEARCH
|
|
||||||
let scoreQueryObj = prepareQueries(q)
|
|
||||||
|
|
||||||
let [regions] = await Promise.all([getRegions(dbConn)])
|
|
||||||
let data = {
|
|
||||||
regions: regions,
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILTER if query contains filterString
|
|
||||||
if (q.textfilter) {
|
|
||||||
data.regions = filterByString(data.regions, q.textfilter, q.fulltext)
|
|
||||||
}
|
|
||||||
|
|
||||||
scoreAndSearch(data, q.from, q.to, scoreQueryObj).then(searchResults => {
|
|
||||||
|
|
||||||
// only dev:
|
|
||||||
if (process.env.SHOW_MATCH_VALUE === '1') searchResults.forEach(reg => reg.name = `${reg.name} (${_.round(reg.score * 10, 1)}% match)`)
|
|
||||||
|
|
||||||
// FILTER NULLSCORES
|
|
||||||
if (!_.get(q, 'showRegionsWithNullScore', false)) {
|
|
||||||
console.log('without null scores');
|
|
||||||
searchResults.forEach(el => console.log('region:', el.name, 'score:', el.score))
|
|
||||||
searchResults = searchResults.filter(el => !_.some(el.scores, score => _.isNaN(score.score) || _.isNil(score.score) || score.score <= 0))
|
|
||||||
}
|
|
||||||
// SEND RESPONSE
|
|
||||||
res.json(searchResults)
|
|
||||||
|
|
||||||
}).catch(e => {
|
|
||||||
// TODO error handling
|
|
||||||
console.log(e)
|
|
||||||
res.status(400).send(e.message)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterByString(searchResults, filterString, boolFulltext) {
|
|
||||||
return _.filter(searchResults, region => {
|
|
||||||
// console.log("filtering: filterString, boolFulltext");
|
|
||||||
// console.log(filterString, boolFulltext);
|
|
||||||
filterString = filterString.toLowerCase()
|
|
||||||
let name = region.name.toLowerCase()
|
|
||||||
let country = region.country.toLowerCase()
|
|
||||||
if (boolFulltext) {
|
|
||||||
let desc = region.description.toLowerCase()
|
|
||||||
return name.includes(filterString) || country.includes(filterString) || desc.includes(filterString)
|
|
||||||
}
|
|
||||||
return name.includes(filterString) || country.includes(filterString)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareQueries(queries) {
|
|
||||||
let q = {
|
|
||||||
climate: {},
|
|
||||||
costs: {},
|
|
||||||
others: {}
|
|
||||||
}
|
|
||||||
// climate
|
|
||||||
if (queries.temperature_mean_max) q.climate.temperature_mean_max = queries.temperature_mean_max
|
|
||||||
if (queries.precipitation) q.climate.precipitation = queries.precipitation
|
|
||||||
if (queries.rain_days) q.climate.rain_days = queries.rain_days
|
|
||||||
if (queries.sun_hours) q.climate.sun_hours = queries.sun_hours
|
|
||||||
|
|
||||||
// costs
|
|
||||||
if (queries.accommodation_costs) q.costs.accommodation_costs = queries.accommodation_costs
|
|
||||||
if (queries.food_costs) q.costs.food_costs = queries.food_costs
|
|
||||||
if (queries.alcohol_costs) q.costs.alcohol_costs = queries.alcohol_costs
|
|
||||||
if (queries.water_costs) q.costs.water_costs = queries.water_costs
|
|
||||||
if (queries.local_transportation_costs) q.costs.local_transportation_costs = queries.local_transportation_costs
|
|
||||||
if (queries.entertainment_costs) q.costs.entertainment_costs = queries.entertainment_costs
|
|
||||||
if (queries.average_per_day_costs) q.costs.average_per_day_costs = queries.average_per_day_costs
|
|
||||||
|
|
||||||
// others
|
|
||||||
if (queries.avg_price_relative) q.others.avg_price_relative = queries.avg_price_relative
|
|
||||||
if (queries.tags) q.others.tags = queries.tags
|
|
||||||
|
|
||||||
return q
|
|
||||||
}
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* tags:
|
|
||||||
* name: Update
|
|
||||||
* description: Endpoint for updating region specific data. Only for manual use in the prototype application!
|
|
||||||
*/
|
|
||||||
|
|
||||||
const router = require("express").Router();
|
|
||||||
|
|
||||||
// Models
|
|
||||||
const handleClimateUpdate = require("../models/handleClimateUpdate.js")
|
|
||||||
const handleClimateUpdateV2 = require("../models/handleClimateUpdateV2.js")
|
|
||||||
const handleUpdateRegionNearby = require("../models/handleUpdateRegionNearby.js")
|
|
||||||
const handleUpdateRegionNearbyById = require("../models/handleUpdateRegionNearbyById.js")
|
|
||||||
const handleUpdateRegionNearbyImgUrl = require("../models/handleUpdateRegionNearbyImgUrl.js")
|
|
||||||
const handleUpdateRegionNearbyImgUrlById = require("../models/handleUpdateRegionNearbyImgUrlById.js")
|
|
||||||
|
|
||||||
// Utils
|
|
||||||
const sqlSanitzer = require("../util/sqlstring_sanitizer.js")
|
|
||||||
|
|
||||||
module.exports = dbConn => {
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /update/climate/v1:
|
|
||||||
* put:
|
|
||||||
* summary: Pull monthly data from meteostat API V1
|
|
||||||
* tags: [Update]
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Update information is logged in backend
|
|
||||||
*/
|
|
||||||
router.put("/api/v1/update/climate/v1", async (req, res) => {
|
|
||||||
const update = await handleClimateUpdate(dbConn)
|
|
||||||
res.json(update)
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /update/climate/v2:
|
|
||||||
* put:
|
|
||||||
* summary: Pull daily data from meteostat API V2. Data is written to Travopti database and must be processed manually before it can be used.
|
|
||||||
* tags: [Update]
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Update information is logged in backend
|
|
||||||
*/
|
|
||||||
router.put("/api/v1/update/climate/v2", async (req, res) => {
|
|
||||||
const update = await handleClimateUpdateV2(dbConn)
|
|
||||||
res.json(update)
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /update/regions/all/nearby:
|
|
||||||
* put:
|
|
||||||
* summary: Updates all nearby data for all regions
|
|
||||||
* tags: [Update]
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Updates all nearby data for all regions
|
|
||||||
*/
|
|
||||||
router.put("/api/v1/update/regions/all/nearby", async (req, res) => {
|
|
||||||
res.json(await handleUpdateRegionNearby(dbConn))
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /update/regions/all/lonlat:
|
|
||||||
* put:
|
|
||||||
* summary: Updates all coordinate data for all regions
|
|
||||||
* tags: [Update]
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Updates all coordinate data for all regions
|
|
||||||
*/
|
|
||||||
router.put("/api/v1/update/regions/all/lonlat", async (req,res) => {
|
|
||||||
res.json(await handleRegionLonLat(dbConn))
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /update/regions/all/nearby/image:
|
|
||||||
* put:
|
|
||||||
* summary: Updates the nearby image urls for all regions
|
|
||||||
* tags: [Update]
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Updates the nearby image urls for all regions
|
|
||||||
*/
|
|
||||||
router.put("/api/v1/update/regions/all/nearby/image", async (req, res) => {
|
|
||||||
res.json(await handleUpdateRegionNearbyImgUrl(dbConn))
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /update/regions/{id}/nearby:
|
|
||||||
* put:
|
|
||||||
* summary: Updates the nearby data for a specific region
|
|
||||||
* tags: [Update]
|
|
||||||
* parameters:
|
|
||||||
* - name: "id"
|
|
||||||
* in: "path"
|
|
||||||
* required: true
|
|
||||||
* type: int
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Updates the nearby data for a specific region
|
|
||||||
*/
|
|
||||||
router.put("/api/v1/update/regions/:id/nearby", async (req, res) => {
|
|
||||||
const id = sqlSanitzer(req.params.id);
|
|
||||||
res.json(await handleUpdateRegionNearbyById(dbConn, id))
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /update/regions/{id}/nearby/image:
|
|
||||||
* put:
|
|
||||||
* summary: Updates the nearby image urls for a specific region
|
|
||||||
* tags: [Update]
|
|
||||||
* parameters:
|
|
||||||
* - name: "id"
|
|
||||||
* in: "path"
|
|
||||||
* required: true
|
|
||||||
* type: int
|
|
||||||
* responses:
|
|
||||||
* "200":
|
|
||||||
* description: Updates the nearby image urls for a specific region
|
|
||||||
*/
|
|
||||||
router.put("/api/v1/update/regions/:id/nearby/image", async (req, res) => {
|
|
||||||
const id = sqlSanitzer(req.params.id);
|
|
||||||
res.json(await handleUpdateRegionNearbyImgUrlById(dbConn, id))
|
|
||||||
});
|
|
||||||
|
|
||||||
return router
|
|
||||||
}
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
scoring: {
|
|
||||||
// parameter: [transition range, transition function, transistion slope exponent]
|
|
||||||
temperature_mean_max: [12, 'easeInOut', 2],
|
|
||||||
precipitation: [60, 'easeInOut', 2], // [170, 'easeInOut', 2],
|
|
||||||
rain_days: [5, 'easeInOut', 2],
|
|
||||||
sun_hours: [80, 'easeInOut', 2],
|
|
||||||
|
|
||||||
accommodation_costs: [30, 'linear', null],
|
|
||||||
food_costs: [25, 'linear', null],
|
|
||||||
alcohol_costs: [15, 'linear', null],
|
|
||||||
water_costs: [15, 'linear', null],
|
|
||||||
local_transportation_costs: [20, 'linear', null],
|
|
||||||
entertainment_costs: [20, 'easeInOut', 0.6],
|
|
||||||
average_per_day_costs: [100, 'linear', null],
|
|
||||||
|
|
||||||
avg_price_relative: [30, 'easeOut', 2],
|
|
||||||
},
|
|
||||||
boundaries: {
|
|
||||||
climate: {
|
|
||||||
min: {
|
|
||||||
temperature_mean: -9.6,
|
|
||||||
temperature_mean_min: -14.5,
|
|
||||||
temperature_mean_max: -4.7,
|
|
||||||
precipitation: 0,
|
|
||||||
rain_days: 0,
|
|
||||||
sun_hours: 3
|
|
||||||
},
|
|
||||||
max: {
|
|
||||||
temperature_mean: 38.3,
|
|
||||||
temperature_mean_min: 33.5,
|
|
||||||
temperature_mean_max: 43.7,
|
|
||||||
precipitation: 1145,
|
|
||||||
rain_days: 28,
|
|
||||||
sun_hours: 416
|
|
||||||
}
|
|
||||||
},
|
|
||||||
static: {
|
|
||||||
max: {
|
|
||||||
accommodation_costs: 500,
|
|
||||||
food_costs: 100,
|
|
||||||
alcohol_costs: 100,
|
|
||||||
water_costs: 100,
|
|
||||||
local_transportation_costs: 100,
|
|
||||||
entertainment_costs: 100,
|
|
||||||
average_per_day_costs: 1000,
|
|
||||||
avg_price_relative: 100
|
|
||||||
|
|
||||||
},
|
|
||||||
min: {
|
|
||||||
accommodation_costs: 0,
|
|
||||||
food_costs: 0,
|
|
||||||
alcohol_costs: 0,
|
|
||||||
water_costs: 0,
|
|
||||||
local_transportation_costs: 0,
|
|
||||||
entertainment_costs: 0,
|
|
||||||
average_per_day_costs: 0,
|
|
||||||
avg_price_relative: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
/**
|
|
||||||
* Encodes an object as base64 string..
|
|
||||||
* @param obj The object to encode
|
|
||||||
*/
|
|
||||||
exports.objToBase64 = function(obj) {
|
|
||||||
return btoa(JSON.stringify(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes a base64 encoded object.
|
|
||||||
* @param base64 Encoded object
|
|
||||||
*/
|
|
||||||
exports.base64ToObj = function(base64) {
|
|
||||||
return JSON.parse(atob(base64));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes a base64 encoded object.
|
|
||||||
* @param base64 encoded object
|
|
||||||
* @returns {string} decoded object
|
|
||||||
*/
|
|
||||||
function atob(base64) {
|
|
||||||
return Buffer.from(base64, 'base64').toString('binary')
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes an object as base64 string.
|
|
||||||
* @param string The object to encode
|
|
||||||
* @returns {string} base64 encoded object
|
|
||||||
*/
|
|
||||||
function btoa(string) {
|
|
||||||
return Buffer.from(string).toString('base64')
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* Seperate Strings created via GROUP_CONCAT by database into an array
|
|
||||||
* @param array String with comma-seperated values
|
|
||||||
* @returns [float] array of float values
|
|
||||||
*/
|
|
||||||
module.exports = (array) => {
|
|
||||||
if (array !== null && array !== undefined) {
|
|
||||||
const value = array
|
|
||||||
array = value.split(",");
|
|
||||||
for (i = 0; i < array.length; i++) {
|
|
||||||
array[i] = parseFloat(array[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
const mariadb = require("mariadb");
|
|
||||||
let dbConn;
|
|
||||||
let conPool;
|
|
||||||
// mariadb doc: https://github.com/MariaDB/mariadb-connector-nodejs/blob/master/documentation/promise-api.md
|
|
||||||
|
|
||||||
async function reconnect() {
|
|
||||||
try {
|
|
||||||
dbConn = await conPool.getConnection();
|
|
||||||
} catch (e) {
|
|
||||||
if (e.code === "ECONNREFUSED") {
|
|
||||||
let err = new Error("Lost connection to the database");
|
|
||||||
err.code = "ERR_DB_CONN_LOST";
|
|
||||||
throw err;
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = async config => {
|
|
||||||
conPool = mariadb.createPool({
|
|
||||||
host: process.env.DB_HOST,
|
|
||||||
user: process.env.DB_USER,
|
|
||||||
password: process.env.DB_PASSWORD,
|
|
||||||
port: process.env.DB_PORT,
|
|
||||||
database: process.env.DATABASE,
|
|
||||||
connectionLimit: 10
|
|
||||||
});
|
|
||||||
|
|
||||||
dbConn = await conPool.getConnection();
|
|
||||||
return {
|
|
||||||
async query(q, p) {
|
|
||||||
let res;
|
|
||||||
try {
|
|
||||||
res = await dbConn.query(q, p);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.code === "ER_CMD_CONNECTION_CLOSED") {
|
|
||||||
await reconnect();
|
|
||||||
await this.query(q, p);
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
module.exports = function (dbConn) {
|
|
||||||
return async function getAllRegionsWithClimatePerMonth(month) {
|
|
||||||
console.log('getAllRegionsWithClimatePerMonth')
|
|
||||||
const sql = `SELECT
|
|
||||||
region_climate.region_id AS region_id,
|
|
||||||
region_climate.month AS month,
|
|
||||||
countries.country AS country,
|
|
||||||
regions.region AS name,
|
|
||||||
ROUND(AVG(region_climate.temperature_mean), 1) AS temperature_mean,
|
|
||||||
ROUND(AVG(region_climate.temperature_mean_min), 1) AS temperature_mean_min,
|
|
||||||
ROUND(AVG(region_climate.temperature_mean_max), 1) AS temperature_mean_max,
|
|
||||||
ROUND(AVG(region_climate.precipitation), 1) AS precipitation,
|
|
||||||
ROUND(AVG(region_climate.raindays), 1) AS rain_days,
|
|
||||||
ROUND(AVG(region_climate.sunshine), 1) AS sun_hours
|
|
||||||
FROM region_climate
|
|
||||||
JOIN regions ON region_climate.region_id = regions.id
|
|
||||||
JOIN countries ON regions.country_id = countries.id
|
|
||||||
WHERE region_climate.month = ${month} GROUP BY region_id`
|
|
||||||
let response = await dbConn.query(sql)
|
|
||||||
console.log(response[0]);
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
exports.getClimateMinMax = async function (dbConn) {
|
|
||||||
console.log('getClimateMinMax')
|
|
||||||
const sqlMin = `SELECT
|
|
||||||
MIN(temperature_mean) AS temperature_mean,
|
|
||||||
MIN(temperature_mean_min) AS temperature_mean_min,
|
|
||||||
MIN(temperature_mean_max) AS temperature_mean_max,
|
|
||||||
MIN(precipitation) AS precipitation,
|
|
||||||
MIN(rain_days) AS rain_days,
|
|
||||||
MIN(sun_hours) AS sun_hours
|
|
||||||
FROM region_climate`
|
|
||||||
const sqlMax = `SELECT
|
|
||||||
MAX(temperature_mean) AS temperature_mean,
|
|
||||||
MAX(temperature_mean_min) AS temperature_mean_min,
|
|
||||||
MAX(temperature_mean_max) AS temperature_mean_max,
|
|
||||||
MAX(precipitation) AS precipitation,
|
|
||||||
MAX(rain_days) AS rain_days,
|
|
||||||
MAX(sun_hours) AS sun_hours
|
|
||||||
FROM region_climate`
|
|
||||||
const [qResMin, qResMax] = await Promise.all([dbConn.query(sqlMin), dbConn.query(sqlMax)])
|
|
||||||
// console.log(qResMin)
|
|
||||||
return { min: qResMin[0], max: qResMax[0] }
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
function getClimatePerRegionAndMonth(regionId, month) {
|
|
||||||
console.log('getClimatePerRegionAndMonth')
|
|
||||||
const sql = `SELECT region_id, AVG(temperature_mean), AVG(temperature_mean_min), AVG(temperature_mean_max), AVG(precipitation), AVG(sunshine) FROM region_climate WHERE month = ${month} AND region_id = ${regionId}`
|
|
||||||
return getQueryRows(sql)
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
module.exports = function (queries) {
|
|
||||||
let res = _.clone(queries)
|
|
||||||
console.log(res);
|
|
||||||
|
|
||||||
// try {
|
|
||||||
if (queries.temperature_mean_max) res.temperature_mean_max = [Number(queries.temperature_mean_max.split(',')[0]), Number(queries.temperature_mean_max.split(',')[1])]
|
|
||||||
if (queries.precipitation) res.precipitation = [Number(queries.precipitation.split(',')[0]), Number(queries.precipitation.split(',')[1])]
|
|
||||||
if (queries.rain_days) res.rain_days = [Number(queries.rain_days.split(',')[0]), Number(queries.rain_days.split(',')[1])]
|
|
||||||
if (queries.sun_hours) res.sun_hours = [Number(queries.sun_hours.split(',')[0]), Number(queries.sun_hours.split(',')[1])]
|
|
||||||
|
|
||||||
if (queries.accommodation_costs) res.accommodation_costs = [Number(queries.accommodation_costs.split(',')[0]), Number(queries.accommodation_costs.split(',')[1])]
|
|
||||||
if (queries.food_costs) res.food_costs = [Number(queries.food_costs.split(',')[0]), Number(queries.food_costs.split(',')[1])]
|
|
||||||
if (queries.alcohol_costs) res.alcohol_costs = [Number(queries.alcohol_costs.split(',')[0]), Number(queries.alcohol_costs.split(',')[1])]
|
|
||||||
if (queries.water_costs) res.water_costs = [Number(queries.water_costs.split(',')[0]), Number(queries.water_costs.split(',')[1])]
|
|
||||||
if (queries.local_transportation_costs) res.local_transportation_costs = [Number(queries.local_transportation_costs.split(',')[0]), Number(queries.local_transportation_costs.split(',')[1])]
|
|
||||||
if (queries.entertainment_costs) res.entertainment_costs = [Number(queries.entertainment_costs.split(',')[0]), Number(queries.entertainment_costs.split(',')[1])]
|
|
||||||
if (queries.average_per_day_costs) res.average_per_day_costs = [Number(queries.average_per_day_costs.split(',')[0]), Number(queries.average_per_day_costs.split(',')[1])]
|
|
||||||
|
|
||||||
if (queries.avg_price_relative) res.avg_price_relative = [Number(queries.avg_price_relative.split(',')[0]), Number(queries.avg_price_relative.split(',')[1])]
|
|
||||||
if (queries.tags) {
|
|
||||||
res.tags = []
|
|
||||||
if (queries.tags.includes(',')) {
|
|
||||||
res.tags.push(...queries.tags.split(',').map(el => el.trim()))
|
|
||||||
} else {
|
|
||||||
res.tags.push(queries.tags)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// console.log(res);
|
|
||||||
|
|
||||||
// console.log('queries successfully transformed');
|
|
||||||
// } catch (error) {
|
|
||||||
// console.log('oldToNewQuerySyntax error');
|
|
||||||
// return queries
|
|
||||||
// }
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
exports.calculateAvgScore = (...scores) => {
|
|
||||||
return avgScore = scores.reduce((total, score) => total += score) / scores.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.calculateScoreRange = (transitionRange, regionVal, sLowVal, sHighVal) => {
|
|
||||||
//console.log('scores.calculateScoreRange:', min, max, multiplier, regionVal, sLowVal, sHighVal)
|
|
||||||
// return full score when in range
|
|
||||||
if (regionVal >= sLowVal && regionVal <= sHighVal) return 10;
|
|
||||||
// choose value with smallest distance
|
|
||||||
let sVal = Math.abs(regionVal - sLowVal) < Math.abs(regionVal - sHighVal) ? sLowVal : sHighVal;
|
|
||||||
return this.calculateScore(transitionRange, regionVal, sVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.calculateScore = (transitionRange, regionVal, searchVal) => {
|
|
||||||
let score = 1 - (Math.abs(searchVal - regionVal) / transitionRange);
|
|
||||||
return (score) * 10;
|
|
||||||
//return score <= 0 ? 0 : score * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.linear = function (x, exponent) {
|
|
||||||
if (x < 0) return 0
|
|
||||||
if (x > 10) return 10
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.easeOut = function (x, exponent) {
|
|
||||||
if (x < 0) return 0
|
|
||||||
if (x > 10) return 10
|
|
||||||
return (1 - Math.pow(1 - (x / 10), exponent)) * 10
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.easeInOut = function (sc, exponent) {
|
|
||||||
const x = (sc ) / 10
|
|
||||||
// console.log(sc, x);
|
|
||||||
if (x<0) return 0
|
|
||||||
if (x>1) return 10
|
|
||||||
return x < 0.5 ? Math.pow(2, exponent-1) * Math.pow(x,exponent) * 10 : (1 - Math.pow(-2 * x + 2, exponent)/2) * 10
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.easeInOutAsymmetric = function (sc, exponent) {
|
|
||||||
const x = (sc ) / 10
|
|
||||||
// console.log(sc, x);
|
|
||||||
if (x<0) return 0
|
|
||||||
if (x>1) return 10
|
|
||||||
return x < 0.5 ? (2 * x) - 0.5 * 10 : (1 - Math.pow(-2 * x + 2, exponent)/2) * 10
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.sigmoid = function (x, exponent) {
|
|
||||||
// const sigm = (1 / (1 + Math.pow(Math.E, 5 * -x))) * 10 + 5
|
|
||||||
// const sigm = 10 / (1 + Math.pow(Math.E, 1.2 * -x + 6))
|
|
||||||
const sigm = 10 / (1 + 8 * Math.pow(Math.E, 3/4 * -x))
|
|
||||||
console.log('sigmoid (IN/OUT):', _.round(x,3), _.round(sigm, 3))
|
|
||||||
return sigm
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.increaseTransitionForHighValues = function (transitionRange, searchVal) {
|
|
||||||
//console.log(transitionRange);
|
|
||||||
// console.log(transitionRange);
|
|
||||||
// console.log(((Math.pow(searchVal / 20, 2) / 100) + 1));
|
|
||||||
// console.log(((Math.pow(searchVal / 20, 2) / 100) + 1) * transitionRange);
|
|
||||||
let transFactor = ((Math.pow(searchVal / 20, 2) / 100) + 1)
|
|
||||||
|
|
||||||
return transFactor >= 4 ? 4 * transitionRange : transFactor * transitionRange
|
|
||||||
}
|
|
||||||