mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
fix(webapp): catch possibe errors on request geolocation (#8640)
* catch possibe errors on request geolocation * proper toast error * remove deprecated request package, use node fetch instead, set timeout --------- Co-authored-by: Max <maxharz@gmail.com> Co-authored-by: Wolfgang Huß <wolle.huss@pjannto.com>
This commit is contained in:
parent
a8de785783
commit
4eff0fb497
@ -83,7 +83,6 @@
|
|||||||
"nodemailer-html-to-text": "^3.2.0",
|
"nodemailer-html-to-text": "^3.2.0",
|
||||||
"preview-email": "^3.1.0",
|
"preview-email": "^3.1.0",
|
||||||
"pug": "^3.0.3",
|
"pug": "^3.0.3",
|
||||||
"request": "~2.88.2",
|
|
||||||
"sanitize-html": "~2.17.0",
|
"sanitize-html": "~2.17.0",
|
||||||
"slug": "~9.1.0",
|
"slug": "~9.1.0",
|
||||||
"trunc-html": "~1.1.2",
|
"trunc-html": "~1.1.2",
|
||||||
|
|||||||
@ -6,27 +6,15 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
/* eslint-disable promise/avoid-new */
|
/* eslint-disable n/no-unsupported-features/node-builtins */
|
||||||
/* eslint-disable promise/prefer-await-to-callbacks */
|
|
||||||
import { UserInputError } from 'apollo-server'
|
import { UserInputError } from 'apollo-server'
|
||||||
import request from 'request'
|
|
||||||
|
|
||||||
import CONFIG from '@config/index'
|
import CONFIG from '@config/index'
|
||||||
|
|
||||||
const fetch = (url) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
request(url, function (error, response, body) {
|
|
||||||
if (error) {
|
|
||||||
reject(error)
|
|
||||||
} else {
|
|
||||||
resolve(JSON.parse(body))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const locales = ['en', 'de', 'fr', 'nl', 'it', 'es', 'pt', 'pl', 'ru']
|
const locales = ['en', 'de', 'fr', 'nl', 'it', 'es', 'pt', 'pl', 'ru']
|
||||||
|
|
||||||
|
const REQUEST_TIMEOUT = 3000
|
||||||
|
|
||||||
const createLocation = async (session, mapboxData) => {
|
const createLocation = async (session, mapboxData) => {
|
||||||
const data = {
|
const data = {
|
||||||
id: mapboxData.id + (mapboxData.address ? `-${mapboxData.address}` : ''),
|
id: mapboxData.id + (mapboxData.address ? `-${mapboxData.address}` : ''),
|
||||||
@ -78,74 +66,80 @@ export const createOrUpdateLocations = async (nodeLabel, nodeId, locationName, s
|
|||||||
|
|
||||||
let locationId
|
let locationId
|
||||||
|
|
||||||
if (locationName !== null) {
|
try {
|
||||||
const res: any = await fetch(
|
if (locationName !== null) {
|
||||||
`https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(
|
const response: any = await fetch(
|
||||||
locationName,
|
`https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(
|
||||||
)}.json?access_token=${
|
locationName,
|
||||||
CONFIG.MAPBOX_TOKEN
|
)}.json?access_token=${
|
||||||
}&types=region,place,country,address&language=${locales.join(',')}`,
|
CONFIG.MAPBOX_TOKEN
|
||||||
)
|
}&types=region,place,country,address&language=${locales.join(',')}`,
|
||||||
|
{
|
||||||
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if (!res?.features?.[0]) {
|
const res = await response.json()
|
||||||
throw new UserInputError('locationName is invalid')
|
|
||||||
}
|
|
||||||
|
|
||||||
let data
|
if (!res?.features?.[0]) {
|
||||||
|
throw new UserInputError('locationName is invalid')
|
||||||
res.features.forEach((item) => {
|
|
||||||
if (item.matching_place_name === locationName) {
|
|
||||||
data = item
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
if (!data) {
|
|
||||||
data = res.features[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data?.place_type?.length) {
|
let data
|
||||||
throw new UserInputError('locationName is invalid')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.place_type.length > 1) {
|
res.features.forEach((item) => {
|
||||||
data.id = 'region.' + data.id.split('.')[1]
|
if (item.matching_place_name === locationName) {
|
||||||
}
|
data = item
|
||||||
await createLocation(session, data)
|
}
|
||||||
|
})
|
||||||
|
if (!data) {
|
||||||
|
data = res.features[0]
|
||||||
|
}
|
||||||
|
|
||||||
let parent = data
|
if (!data?.place_type?.length) {
|
||||||
|
throw new UserInputError('locationName is invalid')
|
||||||
|
}
|
||||||
|
|
||||||
if (parent.address) {
|
if (data.place_type.length > 1) {
|
||||||
parent.id += `-${parent.address}`
|
data.id = 'region.' + data.id.split('.')[1]
|
||||||
}
|
}
|
||||||
|
await createLocation(session, data)
|
||||||
|
|
||||||
if (data.context) {
|
let parent = data
|
||||||
for await (const ctx of data.context) {
|
|
||||||
await createLocation(session, ctx)
|
if (parent.address) {
|
||||||
await session.writeTransaction((transaction) => {
|
parent.id += `-${parent.address}`
|
||||||
return transaction.run(
|
}
|
||||||
`
|
|
||||||
|
if (data.context) {
|
||||||
|
for await (const ctx of data.context) {
|
||||||
|
await createLocation(session, ctx)
|
||||||
|
await session.writeTransaction((transaction) => {
|
||||||
|
return transaction.run(
|
||||||
|
`
|
||||||
MATCH (parent:Location {id: $parentId}), (child:Location {id: $childId})
|
MATCH (parent:Location {id: $parentId}), (child:Location {id: $childId})
|
||||||
MERGE (child)<-[:IS_IN]-(parent)
|
MERGE (child)<-[:IS_IN]-(parent)
|
||||||
RETURN child.id, parent.id
|
RETURN child.id, parent.id
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
parentId: parent.id,
|
parentId: parent.id,
|
||||||
childId: ctx.id,
|
childId: ctx.id,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
parent = ctx
|
parent = ctx
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locationId = data.id
|
||||||
|
} else {
|
||||||
|
locationId = 'non-existent-id'
|
||||||
}
|
}
|
||||||
|
|
||||||
locationId = data.id
|
// delete all current locations from node and add new location
|
||||||
} else {
|
await session.writeTransaction((transaction) => {
|
||||||
locationId = 'non-existent-id'
|
return transaction.run(
|
||||||
}
|
`
|
||||||
|
|
||||||
// delete all current locations from node and add new location
|
|
||||||
await session.writeTransaction((transaction) => {
|
|
||||||
return transaction.run(
|
|
||||||
`
|
|
||||||
MATCH (node:${nodeLabel} {id: $nodeId})
|
MATCH (node:${nodeLabel} {id: $nodeId})
|
||||||
OPTIONAL MATCH (node)-[relationship:IS_IN]->(:Location)
|
OPTIONAL MATCH (node)-[relationship:IS_IN]->(:Location)
|
||||||
DELETE relationship
|
DELETE relationship
|
||||||
@ -154,18 +148,29 @@ export const createOrUpdateLocations = async (nodeLabel, nodeId, locationName, s
|
|||||||
MERGE (node)-[:IS_IN]->(location)
|
MERGE (node)-[:IS_IN]->(location)
|
||||||
RETURN location.id, node.id
|
RETURN location.id, node.id
|
||||||
`,
|
`,
|
||||||
{ nodeId, locationId },
|
{ nodeId, locationId },
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const queryLocations = async ({ place, lang }) => {
|
export const queryLocations = async ({ place, lang }) => {
|
||||||
const res: any = await fetch(
|
try {
|
||||||
`https://api.mapbox.com/geocoding/v5/mapbox.places/${place}.json?access_token=${CONFIG.MAPBOX_TOKEN}&types=region,place,country&language=${lang}`,
|
const res: any = await fetch(
|
||||||
)
|
`https://api.mapbox.com/geocoding/v5/mapbox.places/${place}.json?access_token=${CONFIG.MAPBOX_TOKEN}&types=region,place,country&language=${lang}`,
|
||||||
// Return empty array if no location found or error occurred
|
{
|
||||||
if (!res?.features) {
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT),
|
||||||
return []
|
},
|
||||||
|
)
|
||||||
|
const response = await res.json()
|
||||||
|
// Return empty array if no location found or error occurred
|
||||||
|
if (!response?.features) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return response.features
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error)
|
||||||
}
|
}
|
||||||
return res.features
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -107,19 +107,26 @@ export default {
|
|||||||
this.cities = []
|
this.cities = []
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.loadingGeo = true
|
|
||||||
|
|
||||||
const place = encodeURIComponent(value)
|
try {
|
||||||
const lang = this.$i18n.locale()
|
this.loadingGeo = true
|
||||||
|
|
||||||
const {
|
const place = encodeURIComponent(value)
|
||||||
data: { queryLocations: result },
|
const lang = this.$i18n.locale()
|
||||||
} = await this.$apollo.query({ query: queryLocations(), variables: { place, lang } })
|
|
||||||
|
|
||||||
this.cities = this.processLocationsResult(result)
|
const {
|
||||||
this.loadingGeo = false
|
data: { queryLocations: result },
|
||||||
|
} = await this.$apollo.query({ query: queryLocations(), variables: { place, lang } })
|
||||||
|
|
||||||
return this.cities.find((city) => city.value === value)
|
this.cities = this.processLocationsResult(result)
|
||||||
|
this.loadingGeo = false
|
||||||
|
|
||||||
|
return this.cities.find((city) => city.value === value)
|
||||||
|
} catch (error) {
|
||||||
|
this.$toast.error(error.message)
|
||||||
|
} finally {
|
||||||
|
this.loadingGeo = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
clearLocationName(event) {
|
clearLocationName(event) {
|
||||||
event.target.value = ''
|
event.target.value = ''
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user