Skip to content

Commit

Permalink
Make postal areas API route asynchronous
Browse files Browse the repository at this point in the history
  • Loading branch information
FLoreauIGN committed Apr 26, 2024
1 parent 4b5c11a commit 69aba5e
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 25 deletions.
74 changes: 74 additions & 0 deletions lib/api/consumers/api-consumer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {dataValidationReportFrom, formatObjectWithDefaults, addOrUpdateJob, form
import {addressDefaultOptionalValues} from '../address/schema.js'
import {commonToponymDefaultOptionalValues} from '../common-toponym/schema.js'
import {districtDefaultOptionalValues} from '../district/schema.js'
import {getAllPostalAreas, updatePostalAreas} from '../postal-code/models.js'

const exportToExploitationDBQueue = queue('export-to-exploitation-db')
const exportToExploitationDBJobDelay = process.env.EXPORT_TO_EXPLOITATION_DB_JOB_DELAY || 10_000
Expand All @@ -26,6 +27,9 @@ export default async function apiConsumers({data: {dataType, jobType, data, stat
case 'district':
await districtConsumer(jobType, data, statusID)
break
case 'postalCode':
await postalCodeConsumer(jobType, data, statusID)
break
default:
console.warn(`Consumer Warn: Unknown data type : '${dataType}'`)
}
Expand Down Expand Up @@ -282,6 +286,76 @@ const districtConsumer = async (jobType, payload, statusID) => {
}
}

const postalCodeConsumer = async (jobType, payload, statusID) => {
const checkRequestData = async (payload, jobType) => {
switch (jobType) {
case 'update':
return {isValid: Boolean(payload.operations && payload.expiredPostalAreas)}
default:
return dataValidationReportFrom(false, 'Unknown action type', {actionType: jobType, payload})
}
}

const formatPayloadPostalAreas = async function (payload) {
const postalCodeDBResponse = await getAllPostalAreas() || []
const postalCodesFromDB = new Set(postalCodeDBResponse.map(({postalCode}) => postalCode))

const {features, crs} = payload || {}

const bulkOperations = features.map(({properties, geometry}) => {
const postalCode = properties.cp
postalCodesFromDB.delete(postalCode)
if (geometry.crs === undefined) {
geometry.crs = crs
}

return {postalCode, geometry}
})

return {operations: bulkOperations, expiredPostalAreas: postalCodesFromDB}
}

const formatRequestData = async (payload, jobType) => {
switch (jobType) {
case 'update':
case 'patch':
return formatPayloadPostalAreas(payload, jobType)
default:
console.warn(`District Consumer Warn: Unknown job type : '${jobType}'`)
}
}

const formattedPayload = await formatRequestData(payload, jobType)
const requestDataValidationReport = await checkRequestData(formattedPayload, jobType)
if (requestDataValidationReport.isValid) {
switch (jobType) {
case 'update': {
await updatePostalAreas(formattedPayload)
break
}

default:
console.warn(`PostalCode Consumer Warn: Unknown job type : '${jobType}'`)
}

await setJobStatus(statusID, {
status: 'success',
dataType: 'district',
jobType,
count: payload.length,
})
} else {
await setJobStatus(statusID, {
status: 'error',
dataType: 'district',
jobType,
count: payload.length,
message: 'districts are not valid',
report: requestDataValidationReport.report,
})
}
}

export const extractRelatedDistrictIDs = async (dataType, jobType, payload) => {
switch (dataType) {
case 'address':
Expand Down
6 changes: 6 additions & 0 deletions lib/api/postal-code/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ export const putPostalAreas = postalAreas => PostalArea.bulkCreate(postalAreas,
export const deletePostalAreas = postalCodes => {
postalCodes.map(postalCode => PostalArea.destroy({where: {postalCode}}))
}

export const updatePostalAreas = async ({operations, expiredPostalAreas}) => {
const bulkPostalCode = putPostalAreas(operations)
const deletePostalCode = expiredPostalAreas.size > 0 ? deletePostalAreas([...expiredPostalAreas]) : true
return Promise.all([bulkPostalCode, deletePostalCode])
}
56 changes: 31 additions & 25 deletions lib/api/postal-code/routes.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
import 'dotenv/config.js' // eslint-disable-line import/no-unassigned-import
import {customAlphabet} from 'nanoid'
import express from 'express'
import queue from '../../util/queue.cjs'
import auth from '../../middleware/auth.js'
import {getAllPostalAreas, putPostalAreas, deletePostalAreas} from './models.js'

Check failure on line 6 in lib/api/postal-code/routes.js

View workflow job for this annotation

GitHub Actions / build (16.x)

'getAllPostalAreas' is defined but never used.

Check failure on line 6 in lib/api/postal-code/routes.js

View workflow job for this annotation

GitHub Actions / build (16.x)

'putPostalAreas' is defined but never used.

Check failure on line 6 in lib/api/postal-code/routes.js

View workflow job for this annotation

GitHub Actions / build (16.x)

'deletePostalAreas' is defined but never used.

const app = new express.Router()

app.route('/')
.put(auth, async (req, res) => {
const postalCodeDBResponse = await getAllPostalAreas() || []
const postalCodesFromDB = new Set(postalCodeDBResponse.map(({postalCode}) => postalCode))

const {features, crs} = req.body || {}

const bulkOperations = features.map(({properties, geometry}) => {
const postalCode = properties.cp
postalCodesFromDB.delete(postalCode)
if (geometry.crs === undefined) {
geometry.crs = crs
}
const apiQueue = queue('api')

return {postalCode, geometry}
})
const BAN_API_URL
= process.env.BAN_API_URL || 'https://plateforme.adresse.data.gouv.fr/api'

const bulkPostalCode = putPostalAreas(bulkOperations)
const nanoid = customAlphabet('123456789ABCDEFGHJKMNPQRSTVWXYZ', 9)

const deletePostalCode = postalCodesFromDB.size > 0 ? deletePostalAreas([...postalCodesFromDB]) : true

const operations = await Promise.all([bulkPostalCode, deletePostalCode])
const app = new express.Router()

res.send(
{
app.route('/')
.put(auth, async (req, res) => {
let response
try {
const postalAreas = req.body || {}
const statusID = nanoid()

await apiQueue.add(
{dataType: 'postalArea', jobType: 'update', data: postalAreas, statusID},
{jobId: statusID, removeOnComplete: true}
)
response = {
date: new Date(),
status: 'success',
response: operations,
message: `Check the status of your request : ${BAN_API_URL}/job-status/${statusID}`,
response: {statusID},
}
)
} catch (error) {
response = {
date: new Date(),
status: 'error',
message: error,
response: {},
}
}

res.send(response)
})

export default app

0 comments on commit 69aba5e

Please sign in to comment.