www: Add redis cache and api cookie-based i18n
This commit is contained in:
parent
4bfa6cfe16
commit
d590582a85
27
app.js
27
app.js
@ -1,3 +1,4 @@
|
||||
require('dotenv').config();
|
||||
const createError = require('http-errors');
|
||||
const express = require('express');
|
||||
const session = require('express-session');
|
||||
@ -6,6 +7,13 @@ const path = require('path');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const logger = require('morgan');
|
||||
const i18n = require('i18n-2');
|
||||
const redis = require('redis');
|
||||
|
||||
const [redisHost, redisPort] = [process.env.REDIS_HOST, process.env.REDIS_PORT];
|
||||
const redisClient = redis.createClient(redisPort, redisHost);
|
||||
redisClient.on('error', (error) => {
|
||||
console.error('Redis error:', error);
|
||||
});
|
||||
|
||||
const indexRouter = require('./routes/index');
|
||||
const apiRouter = require('./routes/api');
|
||||
@ -45,18 +53,15 @@ i18n.expressBind(app, {
|
||||
app.use(function (req, res, next) {
|
||||
req.i18n.setLocaleFromQuery();
|
||||
req.i18n.setLocaleFromCookie();
|
||||
next();
|
||||
});
|
||||
|
||||
app.all('*', function(req, res, next) {
|
||||
// set locale
|
||||
// set locale from url prefix
|
||||
var rxLocale = /^\/(fr|en)/i;
|
||||
if(rxLocale.test(req.url)){
|
||||
const arr = rxLocale.exec(req.url);
|
||||
const locale=arr[1];
|
||||
req.i18n.setLocale(locale);
|
||||
} else {
|
||||
req.i18n.setLocale('en');
|
||||
if (rxLocale.test(req.url)) {
|
||||
const arr = rxLocale.exec(req.url);
|
||||
const locale = arr[1];
|
||||
req.i18n.setLocale(locale);
|
||||
}
|
||||
if (req.cookies.locale === undefined) {
|
||||
res.cookie('locale', req.i18n.locale, { maxAge: 90000 });
|
||||
}
|
||||
// add extra logic
|
||||
next();
|
||||
|
@ -1,23 +1,20 @@
|
||||
const debug = require('debug')('soundbirder:api');
|
||||
const debugResponses = require('debug')('soundbirder:api:responses');
|
||||
require('dotenv').config();
|
||||
const axios = require('axios');
|
||||
const eBird = require('@unclesamulus/ebird-api')(process.env.EBIRD_API_KEY);
|
||||
const XenoCanto = require('@unclesamulus/xeno-canto-api');
|
||||
const { choices, choice } = require('../utils/choices');
|
||||
const debug = require('debug')('soundbirder:api');
|
||||
const debugLocale = require('debug')('soundbirder:locale');
|
||||
const debugResponses = require('debug')('soundbirder:api:responses');
|
||||
const quizzController = require('./quizz');
|
||||
|
||||
const OPENCAGE_API_KEY = process.env.OPENCAGE_API_KEY;
|
||||
const OPENCAGE_API_URL = 'https://api.opencagedata.com/geocode/v1/json?q=<lat>+<lon>&key=<key>';
|
||||
const QUIZZ_SIZE = process.env.QUIZZ_SIZE ? process.env.QUIZZ_SIZE : 5;
|
||||
|
||||
function check(req, res) {
|
||||
|
||||
}
|
||||
|
||||
function quizz(req, res) {
|
||||
debug('Generating quizz');
|
||||
const { lat, lng } = req.body;
|
||||
generateQuizz({ lat, lng }, req.locale)
|
||||
const locale = req.i18n.locale;
|
||||
debugLocale("Locale:", locale);
|
||||
quizzController.generateQuizz({ lat, lng }, locale, QUIZZ_SIZE)
|
||||
.then(({ species, correct, audio }) => {
|
||||
req.session.correct = correct;
|
||||
res.json({ species, audio });
|
||||
@ -30,118 +27,11 @@ function quizz(req, res) {
|
||||
});
|
||||
}
|
||||
|
||||
async function generateQuizz(coordinates, locale) {
|
||||
const quizz = {}
|
||||
try {
|
||||
const speciesSelection = await getSpeciesSelection(coordinates);
|
||||
const speciesSelectionLocalized = await getLocalizedNames(speciesSelection, locale);
|
||||
quizz.species = await speciesSelectionLocalized;
|
||||
debug("Got species selection", quizz.species);
|
||||
const answer = await choice(speciesSelectionLocalized);
|
||||
debug("Got answer", answer);
|
||||
quizz.correct = answer.code;
|
||||
quizz.audio = await getAudio(answer.sciName);
|
||||
} catch (error) {
|
||||
debug("Error raised while generating quizz");
|
||||
console.error(error);
|
||||
}
|
||||
return quizz;
|
||||
}
|
||||
|
||||
async function getSpeciesSelection(coordinates) {
|
||||
const { lat, lng } = coordinates;
|
||||
const region = await getRegion(lat, lng);
|
||||
region.country_code = region.country_code.toUpperCase();
|
||||
// const regionCode = await getRegionCode(region);
|
||||
const regionCode = region.country_code;
|
||||
const speciesList = await getSpeciesList(regionCode);
|
||||
const speciesSelection = choices(speciesList, QUIZZ_SIZE);
|
||||
debug("Species proposals:", speciesSelection)
|
||||
return speciesSelection;
|
||||
}
|
||||
|
||||
function getHome(req, res) {
|
||||
res.render('api', {
|
||||
title: "SoundBirder api",
|
||||
version: 0
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getRegion(lat, lon) {
|
||||
const url = OPENCAGE_API_URL
|
||||
.replace('<lat>', lat)
|
||||
.replace('<lon>', lon)
|
||||
.replace('<key>', OPENCAGE_API_KEY);
|
||||
return axios.get(url).then(response => {
|
||||
const { results } = response.data;
|
||||
const { country_code, country, state, county } = results[0].components;
|
||||
return { country_code, country, state, county };
|
||||
}).catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
function getRegionCode({ country_code, country, state, county }) {
|
||||
return eBird.ref.region.list('subnational1', country_code)()
|
||||
.then(states => {
|
||||
console.log(states);
|
||||
const regionCode = states.find(region => region.name === state).code;
|
||||
return regionCode;
|
||||
}).catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
async function getLocalizedNames(speciesCodes, locale) {
|
||||
let names = [];
|
||||
for (let i = 0; i < speciesCodes.length; i++) {
|
||||
const code = speciesCodes[i];
|
||||
const { sciName, comName } = await getLocalizedName(code, locale);
|
||||
names.push({ code, sciName, comName });
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
function getLocalizedName(speciesCode, locale) {
|
||||
return eBird.ref.taxonomy.ebird({
|
||||
fmt: 'json',
|
||||
locale: locale,
|
||||
species: speciesCode
|
||||
}).then(
|
||||
response => {
|
||||
const names = response[0];
|
||||
debug("Got localized species names");
|
||||
debugResponses(names);
|
||||
return names;
|
||||
}
|
||||
).catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
function getSpeciesList(regionCode) {
|
||||
return eBird.product.spplist.in(regionCode)()
|
||||
.then(species => {
|
||||
return species;
|
||||
})
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
function getAudio(speciesScientificName) {
|
||||
return XenoCanto.search({
|
||||
name: speciesScientificName,
|
||||
quality: 'A'
|
||||
}).then(response => {
|
||||
debugResponses(response);
|
||||
const { recordings } = response;
|
||||
const randomRecord = choice(recordings);
|
||||
const audio = randomRecord.file;
|
||||
return audio;
|
||||
}).catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
|
28
controllers/cache.js
Normal file
28
controllers/cache.js
Normal file
@ -0,0 +1,28 @@
|
||||
require('dotenv').config();
|
||||
const debug = require('debug')('soundbirder:cache');
|
||||
const redis = require('redis');
|
||||
[redisHost, redisPort] = [process.env.REDIS_HOST, process.env.REDIS_PORT];
|
||||
const redisClient = redis.createClient(redisPort, redisHost);
|
||||
|
||||
(async () => {
|
||||
redisClient.connect();
|
||||
})();
|
||||
|
||||
function cacheResponse(request, response) {
|
||||
debug("Caching response", request);
|
||||
redisClient.set(request, JSON.stringify(response));
|
||||
}
|
||||
|
||||
async function getCached(request) {
|
||||
debug("Getting cached response", request);
|
||||
const cached = await redisClient.get(request);
|
||||
if (cached) {
|
||||
return JSON.parse(cached);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
cacheResponse,
|
||||
getCached
|
||||
}
|
120
controllers/quizz.js
Normal file
120
controllers/quizz.js
Normal file
@ -0,0 +1,120 @@
|
||||
require('dotenv').config();
|
||||
const debug = require('debug')('soundbirder:api:quizz');
|
||||
const debugResponses = require('debug')('soundbirder:api:responses');
|
||||
const cache = require('./cache');
|
||||
const eBird = require('@unclesamulus/ebird-api')(process.env.EBIRD_API_KEY);
|
||||
const XenoCanto = require('@unclesamulus/xeno-canto-api');
|
||||
const { choices, choice } = require('../utils/choices');
|
||||
const { getRegion } = require('./region');
|
||||
|
||||
async function generateQuizz(coordinates, locale, size) {
|
||||
const quizz = {}
|
||||
try {
|
||||
const speciesSelection = await getSpeciesSelection(coordinates, size);
|
||||
debugResponses(`Species selection: ${speciesSelection}`);
|
||||
const speciesSelectionLocalized = await getLocalizedNames(speciesSelection, locale);
|
||||
debugResponses('Localized species selection:', speciesSelectionLocalized);
|
||||
quizz.species = speciesSelectionLocalized;
|
||||
debug("Got species selection", quizz.species);
|
||||
const answer = await choice(speciesSelectionLocalized);
|
||||
debug("Got answer", answer);
|
||||
quizz.correct = answer.speciesCode;
|
||||
quizz.audio = await getAudio(answer.sciName);
|
||||
debug("Got audio", quizz.audio);
|
||||
} catch (error) {
|
||||
debug("Error raised while generating quizz");
|
||||
console.error(error);
|
||||
}
|
||||
return quizz;
|
||||
}
|
||||
|
||||
async function getSpeciesSelection(coordinates, number) {
|
||||
const { lat, lng } = coordinates;
|
||||
const region = await getRegion(lat, lng);
|
||||
// const regionCode = await getRegionCode(region);
|
||||
const regionCode = region.country_code;
|
||||
const speciesList = await getSpeciesList(regionCode);
|
||||
const speciesSelection = choices(speciesList, number);
|
||||
debug("Species proposals:", speciesSelection)
|
||||
return speciesSelection;
|
||||
}
|
||||
|
||||
|
||||
async function getLocalizedNames(speciesCodes, locale) {
|
||||
let allNames = [];
|
||||
for (let i = 0; i < speciesCodes.length; i++) {
|
||||
const code = speciesCodes[i];
|
||||
let flag = false;
|
||||
try {
|
||||
names = await cache.getCached(`${code}-${locale}`);
|
||||
if (names) {
|
||||
allNames.push(names);
|
||||
flag = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
if (!flag) {
|
||||
try {
|
||||
const names = { speciesCode, sciName, comName } = await getLocalizedName(code, locale);
|
||||
cache.cacheResponse(`${code}-${locale}`, names);
|
||||
allNames.push(names);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
return allNames;
|
||||
}
|
||||
|
||||
function getLocalizedName(speciesCode, locale) {
|
||||
return eBird.ref.taxonomy.ebird({
|
||||
fmt: 'json',
|
||||
locale: locale,
|
||||
species: speciesCode
|
||||
}).then(
|
||||
response => {
|
||||
const names = response[0];
|
||||
debug("Got localized species names");
|
||||
debugResponses(names);
|
||||
return names;
|
||||
}
|
||||
).catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
async function getSpeciesList(regionCode) {
|
||||
const cached = await cache.getCached(`spplist-${regionCode}`);
|
||||
if (cached) {
|
||||
return cached;
|
||||
} else {
|
||||
return eBird.product.spplist.in(regionCode)()
|
||||
.then(species => {
|
||||
cache.cacheResponse(`spplist-${regionCode}`, species);
|
||||
return species;
|
||||
})
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getAudio(speciesScientificName) {
|
||||
return XenoCanto.search({
|
||||
name: speciesScientificName,
|
||||
quality: 'A'
|
||||
}).then(response => {
|
||||
debugResponses(response);
|
||||
const { recordings } = response;
|
||||
const randomRecord = choice(recordings);
|
||||
const audio = randomRecord.file;
|
||||
return audio;
|
||||
}).catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateQuizz
|
||||
}
|
46
controllers/region.js
Normal file
46
controllers/region.js
Normal file
@ -0,0 +1,46 @@
|
||||
require('dotenv').config();
|
||||
const debug = require('debug')('soundbirder:api:region');
|
||||
const cache = require('./cache');
|
||||
const axios = require('axios');
|
||||
|
||||
const OPENCAGE_API_KEY = process.env.OPENCAGE_API_KEY;
|
||||
const OPENCAGE_API_URL = 'https://api.opencagedata.com/geocode/v1/json?q=<lat>+<lon>&key=<key>';
|
||||
|
||||
async function getRegion(lat, lon) {
|
||||
const url = OPENCAGE_API_URL
|
||||
.replace('<lat>', lat)
|
||||
.replace('<lon>', lon)
|
||||
.replace('<key>', OPENCAGE_API_KEY);
|
||||
try {
|
||||
const cached = await cache.getCached(`region-${lat}-${lon}`);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
return axios.get(url).then(response => {
|
||||
const { results } = response.data;
|
||||
const region = results[0].components;
|
||||
region.country_code = region.country_code.toUpperCase();
|
||||
cache.cacheResponse(url, region);
|
||||
return { country_code, country, state, county } = region;
|
||||
}).catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
function getRegionCode({ country_code, country, state, county }) {
|
||||
return eBird.ref.region.list('subnational1', country_code)()
|
||||
.then(states => {
|
||||
console.log(states);
|
||||
const regionCode = states.find(region => region.name === state).code;
|
||||
return regionCode;
|
||||
}).catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getRegion,
|
||||
}
|
158
package-lock.json
generated
158
package-lock.json
generated
@ -23,7 +23,8 @@
|
||||
"leaflet": "^1.8.0",
|
||||
"lodash": "^4.17.21",
|
||||
"morgan": "~1.9.1",
|
||||
"pug": "^3.0.2"
|
||||
"pug": "^3.0.2",
|
||||
"redis": "^4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
@ -66,6 +67,59 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/bloom": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz",
|
||||
"integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/client": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.3.0.tgz",
|
||||
"integrity": "sha512-XCFV60nloXAefDsPnYMjHGtvbtHR8fV5Om8cQ0JYqTNbWcQo/4AryzJ2luRj4blveWazRK/j40gES8M7Cp6cfQ==",
|
||||
"dependencies": {
|
||||
"cluster-key-slot": "1.1.0",
|
||||
"generic-pool": "3.8.2",
|
||||
"yallist": "4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/graph": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz",
|
||||
"integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/json": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz",
|
||||
"integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/search": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz",
|
||||
"integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redis/time-series": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz",
|
||||
"integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==",
|
||||
"peerDependencies": {
|
||||
"@redis/client": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@unclesamulus/ebird-api": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@unclesamulus/ebird-api/-/ebird-api-0.0.0.tgz",
|
||||
@ -209,6 +263,14 @@
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
|
||||
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
|
||||
},
|
||||
"node_modules/cluster-key-slot": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
|
||||
"integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
@ -596,6 +658,14 @@
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"node_modules/generic-pool": {
|
||||
"version": "3.8.2",
|
||||
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz",
|
||||
"integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz",
|
||||
@ -1063,6 +1133,19 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/redis": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-4.3.0.tgz",
|
||||
"integrity": "sha512-RXRUor0iU1vizu4viHoUyLpe1ZO/RngZp0V9DyXBHTI+7tC7rEz6Wzn4Sv9v0tTJeqGAzdJ+q5YVbNKKQ5hX9A==",
|
||||
"dependencies": {
|
||||
"@redis/bloom": "1.0.2",
|
||||
"@redis/client": "1.3.0",
|
||||
"@redis/graph": "1.0.1",
|
||||
"@redis/json": "1.0.3",
|
||||
"@redis/search": "1.1.0",
|
||||
"@redis/time-series": "1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||
@ -1257,6 +1340,11 @@
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@ -1285,6 +1373,46 @@
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@redis/bloom": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz",
|
||||
"integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/client": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.3.0.tgz",
|
||||
"integrity": "sha512-XCFV60nloXAefDsPnYMjHGtvbtHR8fV5Om8cQ0JYqTNbWcQo/4AryzJ2luRj4blveWazRK/j40gES8M7Cp6cfQ==",
|
||||
"requires": {
|
||||
"cluster-key-slot": "1.1.0",
|
||||
"generic-pool": "3.8.2",
|
||||
"yallist": "4.0.0"
|
||||
}
|
||||
},
|
||||
"@redis/graph": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz",
|
||||
"integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/json": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz",
|
||||
"integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/search": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz",
|
||||
"integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/time-series": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz",
|
||||
"integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==",
|
||||
"requires": {}
|
||||
},
|
||||
"@unclesamulus/ebird-api": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@unclesamulus/ebird-api/-/ebird-api-0.0.0.tgz",
|
||||
@ -1404,6 +1532,11 @@
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
|
||||
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
|
||||
},
|
||||
"cluster-key-slot": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
|
||||
"integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw=="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
@ -1692,6 +1825,11 @@
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"generic-pool": {
|
||||
"version": "3.8.2",
|
||||
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz",
|
||||
"integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg=="
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz",
|
||||
@ -2074,6 +2212,19 @@
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"redis": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-4.3.0.tgz",
|
||||
"integrity": "sha512-RXRUor0iU1vizu4viHoUyLpe1ZO/RngZp0V9DyXBHTI+7tC7rEz6Wzn4Sv9v0tTJeqGAzdJ+q5YVbNKKQ5hX9A==",
|
||||
"requires": {
|
||||
"@redis/bloom": "1.0.2",
|
||||
"@redis/client": "1.3.0",
|
||||
"@redis/graph": "1.0.1",
|
||||
"@redis/json": "1.0.3",
|
||||
"@redis/search": "1.1.0",
|
||||
"@redis/time-series": "1.0.3"
|
||||
}
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.22.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||
@ -2217,6 +2368,11 @@
|
||||
"assert-never": "^1.2.1",
|
||||
"babel-walk": "3.0.0-canary-5"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
"leaflet": "^1.8.0",
|
||||
"lodash": "^4.17.21",
|
||||
"morgan": "~1.9.1",
|
||||
"pug": "^3.0.2"
|
||||
"pug": "^3.0.2",
|
||||
"redis": "^4.3.0"
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ async function query(endpoint, params) {
|
||||
function getQuizz(lat, lng) {
|
||||
return query('game/quizz', { lat, lng })
|
||||
.then(data => {
|
||||
console.log(data);
|
||||
return data;
|
||||
}).catch(error => {
|
||||
throw error;
|
||||
|
@ -26,7 +26,10 @@ function geolocationHandler() {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
|
||||
let marker = undefined;
|
||||
let marker = L.marker(location, { draggable: true }).addTo(map);
|
||||
marker.on('dragend', updateMarker);
|
||||
marker.addTo(map);
|
||||
|
||||
// Get geolocation
|
||||
function getLocation() {
|
||||
if (navigator.geolocation) {
|
||||
@ -38,11 +41,7 @@ function geolocationHandler() {
|
||||
|
||||
function setLocation(position) {
|
||||
location = [position.coords.latitude, position.coords.longitude];
|
||||
if (marker === undefined) {
|
||||
marker = new L.marker(location, { draggable: 'true' });
|
||||
marker.on('dragend', updateMarker);
|
||||
marker.addTo(map);
|
||||
} else {
|
||||
if (marker !== undefined) {
|
||||
marker.setLatLng(location);
|
||||
}
|
||||
map.setView(location, 15);
|
||||
|
Loading…
Reference in New Issue
Block a user