Skip to content

Commit

Permalink
Add API route to update districts postal code
Browse files Browse the repository at this point in the history
  • Loading branch information
FLoreauIGN committed Feb 16, 2024
1 parent 5d33597 commit a48ece8
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 3 deletions.
16 changes: 15 additions & 1 deletion lib/api/district/models.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import {Op} from 'sequelize'
import {District} from '../../util/sequelize.js'

export const getDistrict = districtID => District.findByPk(districtID, {raw: true})

export const getDistricts = districtIDs => District.findAll({where: {id: districtIDs}, raw: true})

export const getDistrictsFromCog = cog => District.findAll({where: {meta: {insee: {cog}}}, raw: true})
export const getDistrictFromCog = cog => District.findAll({where: {meta: {insee: {cog}}}, raw: true})

export const getDistrictsFromCog = async cog => {
const districts = await District.findAll({where: {meta: {insee: {cog: {[Op.or]: cog}}}}, raw: true})
const districtsByInseeCode = districts.reduce(
(acc, district) => {
if (!acc[district.meta?.insee?.cog]) {
acc[district.meta.insee.cog] = district
}

return acc
}, {})
return cog.map(codeInsee => districtsByInseeCode[codeInsee] || {})
}

export const setDistricts = districts => District.bulkCreate(districts)

Expand Down
111 changes: 109 additions & 2 deletions lib/api/district/routes.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import 'dotenv/config.js' // eslint-disable-line import/no-unassigned-import
import {customAlphabet} from 'nanoid'
import express from 'express'
import Papa from 'papaparse'
import queue from '../../util/queue.cjs'
import auth from '../../middleware/auth.js'
import analyticsMiddleware from '../../middleware/analytics.js'
import {getDistrict, getDistrictsFromCog, deleteDistrict} from './models.js'
import fetch from '../../util/fetch.cjs'
import {getDistrict, getDistrictFromCog, getDistrictsFromCog, deleteDistrict, patchDistricts} from './models.js'

const apiQueue = queue('api')

Expand Down Expand Up @@ -189,7 +191,7 @@ app.get('/cog/:cog', analyticsMiddleware, async (req, res) => {
let response
try {
const {cog} = req.params
const districts = await getDistrictsFromCog(cog)
const districts = await getDistrictFromCog(cog)

if (!districts || districts.length === 0) {
res.status(404).send('Request ID unknown')
Expand All @@ -215,4 +217,109 @@ app.get('/cog/:cog', analyticsMiddleware, async (req, res) => {
res.send(response)
})

async function updateDbFromDataNova(postalFile) {
/* eslint-disable camelcase */
const headers = {
'#Code_commune_INSEE': 'codeInsee',
Nom_de_la_commune: 'nomCommune',
Code_postal: 'codePostal',
Libellé_d_acheminement: 'libelleAcheminement',
'Libell�_d_acheminement': 'libelleAcheminement', // Postal file url returns wrong header charset code (UTF-8 instead of ISO-8859-1)
Ligne_5: 'ligne5',
}
/* eslint-enable camelcase */

const dataRaw = await Papa.parse(postalFile, {
header: true,
transformHeader: name => headers[name] || name,
skipEmptyLines: true,
})

const districts = await getDistrictsFromCog(
dataRaw.data.map(({codeInsee}) => codeInsee)
)

const districtsByInseeCode = districts.reduce(
(acc, district) => ({
...acc,
...(!district?.meta || acc[district.meta?.insee?.cog] ? {} : {[district.meta.insee.cog]: district}),
}), {})

const banDistricts = Object.values(
(dataRaw?.data || []).map(({codeInsee, codePostal, libelleAcheminement}) => {
const {id} = districtsByInseeCode[codeInsee] || {}
return {id, codePostal: [codePostal], libelleAcheminement}
})
.reduce(
(acc, district) => {
if (district.id) {
if (acc[district.id]) {
acc[district.id].codePostal = [...acc[district.id].codePostal, ...district.codePostal]
} else {
acc[district.id] = district
}
}

return acc
}, {}
)
)

const patchBulkOperations = banDistricts.map(({id, codePostal, libelleAcheminement}) => ({
id,
meta: {
laPoste: {
codePostal,
libelleAcheminement,
source: 'La Poste - dataNOVA',
}
}
}))

patchDistricts(patchBulkOperations)

return banDistricts
}

app.route('/codePostal')
.get(async (req, res) => {
let response
try {
// On February 2024 the postal file url is :
// https://datanova.laposte.fr/data-fair/api/v1/datasets/laposte-hexasmal/raw
const {url} = req.query
const postalFile = await fetch(url)

response = await updateDbFromDataNova(postalFile)
} catch (error) {
const {message} = error
response = {
date: new Date(),
status: 'error',
message,
response: {},
}
}

res.send(response)
})
.post(express.text(), async (req, res) => {
let response
try {
const postalFile = req.body

response = await updateDbFromDataNova(postalFile)
} catch (error) {
const {message} = error
response = {
date: new Date(),
status: 'error',
message,
response: {},
}
}

res.send(response)
})

export default app

0 comments on commit a48ece8

Please sign in to comment.