From d590582a8544dd6ce4abe362f1acd3f8eb43fc57 Mon Sep 17 00:00:00 2001 From: Samuel ORTION Date: Mon, 29 Aug 2022 06:44:58 +0200 Subject: [PATCH] www: Add redis cache and api cookie-based i18n --- app.js | 27 +++--- controllers/api.js | 124 ++---------------------- controllers/cache.js | 28 ++++++ controllers/quizz.js | 120 +++++++++++++++++++++++ controllers/region.js | 46 +++++++++ package-lock.json | 158 ++++++++++++++++++++++++++++++- package.json | 3 +- public/javascripts/api-client.js | 1 - public/javascripts/map.js | 13 ++- 9 files changed, 382 insertions(+), 138 deletions(-) create mode 100644 controllers/cache.js create mode 100644 controllers/quizz.js create mode 100644 controllers/region.js diff --git a/app.js b/app.js index 7c9074b..134deb4 100644 --- a/app.js +++ b/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(); diff --git a/controllers/api.js b/controllers/api.js index 24a94c7..cb16470 100644 --- a/controllers/api.js +++ b/controllers/api.js @@ -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=+&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) - .replace('', lon) - .replace('', 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; }); } diff --git a/controllers/cache.js b/controllers/cache.js new file mode 100644 index 0000000..e9f1357 --- /dev/null +++ b/controllers/cache.js @@ -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 +} \ No newline at end of file diff --git a/controllers/quizz.js b/controllers/quizz.js new file mode 100644 index 0000000..44b348d --- /dev/null +++ b/controllers/quizz.js @@ -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 +} \ No newline at end of file diff --git a/controllers/region.js b/controllers/region.js new file mode 100644 index 0000000..2236cf3 --- /dev/null +++ b/controllers/region.js @@ -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=+&key='; + +async function getRegion(lat, lon) { + const url = OPENCAGE_API_URL + .replace('', lat) + .replace('', lon) + .replace('', 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, +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e7a0fa6..31ab81c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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==" } } } diff --git a/package.json b/package.json index 2a91ef1..1d55bf7 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/public/javascripts/api-client.js b/public/javascripts/api-client.js index 84e4300..b3491ef 100644 --- a/public/javascripts/api-client.js +++ b/public/javascripts/api-client.js @@ -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; diff --git a/public/javascripts/map.js b/public/javascripts/map.js index 1dc791d..aa62aa2 100644 --- a/public/javascripts/map.js +++ b/public/javascripts/map.js @@ -17,7 +17,7 @@ function updateLocationCookies([lat, lng]) { } function geolocationHandler() { - + let location = getCoordinates(); let message = document.querySelector('.message'); // Init map @@ -26,7 +26,10 @@ function geolocationHandler() { attribution: '© OpenStreetMap' }).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);