From 9339a1f574949853b2675d12cf96f6ba95aa5520 Mon Sep 17 00:00:00 2001 From: Arnaud AMBROSELLI Date: Thu, 4 Apr 2024 20:12:29 +0200 Subject: [PATCH] fix: fine tune drinking water --- api-node/data/about/drinking_water.md | 2 -- api-node/data/udi/README.md | 2 +- api-node/package.json | 2 +- api-node/src/aggregators/drinking_water.ts | 10 ++++-- api-node/src/controllers/indicators.ts | 39 ++++++++++++++-------- api-node/src/controllers/udi.ts | 6 ++-- api-node/src/controllers/user.ts | 26 +++++++++++++++ api-node/src/getters/drinking_water.ts | 10 +++--- api-node/src/getters/indicators_list.ts | 1 - 9 files changed, 69 insertions(+), 29 deletions(-) diff --git a/api-node/data/about/drinking_water.md b/api-node/data/about/drinking_water.md index 4eeab37b..1516f179 100644 --- a/api-node/data/about/drinking_water.md +++ b/api-node/data/about/drinking_water.md @@ -1,5 +1,3 @@ -# L’alimentation en eau potable - Le réseau public d’eau potable dessert aujourd’hui la quasi-totalité de la population française, qu’elle habite en milieu urbain ou rural. L’eau du robinet est produite à partir d’eau prélevée par un captage dans une nappe souterraine ou dans une ressource superficielle d’eau douce (fleuves, rivières, canaux, lacs, barrages) ou d’eau de mer. Selon la qualité de l’eau prélevée, différentes étapes de traitement peuvent être nécessaires pour rendre l’eau potable et maintenir sa qualité dans les installations de stockage (réservoirs, châteaux d’eau) et dans les réseaux de distribution, jusqu’au robinet du consommateur. diff --git a/api-node/data/udi/README.md b/api-node/data/udi/README.md index 0704bce1..ea7e6d1d 100644 --- a/api-node/data/udi/README.md +++ b/api-node/data/udi/README.md @@ -13,7 +13,7 @@ Puis nous traduisons les fichiers .json en .sql : `ogr2ogr -f "PGDump" -t_srs EP • `udis` est le nom de la table dans notre base de données (pas de uppercase possible) • `-t_srs EPSG:4326` : pour spécifier le SRID (Spatial Reference Identifier) de la géographie à importer. Ici, 4326 correspond au système de coordonnées WGS 84 (GPS). -Enfin nous enregistrons les données dans notre base de données: `psql "postgresql://recosante:{password}@localhost:5442/recosante" -f bretagne.sql` par exemple +Enfin nous enregistrons les données dans notre base de données: `psql "postgresql://recosante:{password}@localhost:5442/recosante" -f output.sql` par exemple ATTENTION: certains champs des colonnes `wkb_geometry` ou `code_udi` peuvent être nuls, pensez à les supprimer pour ne pas faire bugger Prisma diff --git a/api-node/package.json b/api-node/package.json index 28ca3dae..802418c0 100644 --- a/api-node/package.json +++ b/api-node/package.json @@ -6,7 +6,7 @@ "scripts": { "pre:dev": "npm run prisma-setup && cross-env NODE_ENV=development npx prisma db push && npm run format && npm run ts:check", "dev": "npm run pre:dev && tsx watch ./src/index.ts", - "dev-cronjobs": "npm run pre:dev && cross-env NODE_ENV=development tsx watch ./src/cronjobs/index.ts", + "dev-cronjobs": "npm run pre:dev && cross-env NODE_ENV=development tsx ./src/cronjobs/index.ts", "start": "cross-env NODE_ENV=production npm run prisma-setup && npm run prisma-deploy && tsx ./src/index.ts", "start-cronjobs": "cross-env NODE_ENV=production npm run prisma-setup && npm run prisma-deploy && tsx ./src/cronjobs/index.ts", "prisma-setup": "prisma generate && prisma migrate deploy", diff --git a/api-node/src/aggregators/drinking_water.ts b/api-node/src/aggregators/drinking_water.ts index 7490f0f6..55f58f1f 100644 --- a/api-node/src/aggregators/drinking_water.ts +++ b/api-node/src/aggregators/drinking_water.ts @@ -51,9 +51,13 @@ async function getDrinkingWaterIndicator() { logStep('Getting Drinking Waters'); // Step 1: grab the udis list from the database - const udisRows: Record<'udi', User['udi']>[] = - await prisma.$queryRaw`SELECT DISTINCT udi FROM "User";`; - const udis = udisRows.map((row) => row.udi).filter(Boolean); + const udis = await prisma.udis + .findMany({ + select: { + code_udi: true, + }, + }) + .then((udis) => udis.map((udi) => udi.code_udi).filter(Boolean)); let insertedNewRows = 0; let alreadyExistingRows = 0; diff --git a/api-node/src/controllers/indicators.ts b/api-node/src/controllers/indicators.ts index 4fff4d23..b497b410 100644 --- a/api-node/src/controllers/indicators.ts +++ b/api-node/src/controllers/indicators.ts @@ -9,19 +9,32 @@ import { getIndiceAtmoFromMunicipalityAndDate } from '~/getters/indice_atmo'; import { getPollensFromMunicipalityAndDate } from '~/getters/pollens'; import { getWeatherAlertFromMunicipalityAndDate } from '~/getters/weather_alert'; import { indicatorsList } from '~/getters/indicators_list'; -// import { indicatorsMock } from './mocks/indicators'; import { withUser } from '~/middlewares/auth'; import utc from 'dayjs/plugin/utc'; import { getBathingWaterFromMunicipalityAndDate } from '~/getters/bathing_water'; -// import { getDrinkingWaterFromUdi } from '~/getters/drinking_water'; +import { getDrinkingWaterFromUdi } from '~/getters/drinking_water'; +import { IndicatorsSlugEnum } from '@prisma/client'; dayjs.extend(utc); const router = express.Router(); router.get( '/list', - catchErrors(async (_req: express.Request, res: express.Response) => { + withUser, + catchErrors(async (req: RequestWithUser, res: express.Response) => { + if (Number(req.user.appbuild) < 62) { + res + .status(200) + .send({ + ok: true, + data: indicatorsList.filter( + (list) => list.slug !== IndicatorsSlugEnum.drinking_water, + ), + }); + return; + } res.status(200).send({ ok: true, data: indicatorsList }); + return; }), ); @@ -99,16 +112,16 @@ router.get( if (bathingWater) indicators.push(bathingWater); - // const drinkingWater = await getDrinkingWaterFromUdi({ - // udi: req.user.udi, - // municipality_insee_code, - // date_UTC_ISO: dayjs().utc().toISOString(), - // }); - // if (drinkingWater instanceof Error) { - // next(drinkingWater); - // return; - // } - // if (drinkingWater) indicators.push(drinkingWater); + const drinkingWater = await getDrinkingWaterFromUdi({ + udi: req.user.udi, + municipality_insee_code, + date_UTC_ISO: dayjs().utc().toISOString(), + }); + if (drinkingWater instanceof Error) { + next(drinkingWater); + return; + } + if (drinkingWater) indicators.push(drinkingWater); res.status(200).send({ ok: true, data: indicators }); }, diff --git a/api-node/src/controllers/udi.ts b/api-node/src/controllers/udi.ts index f5082759..e7a7fee0 100644 --- a/api-node/src/controllers/udi.ts +++ b/api-node/src/controllers/udi.ts @@ -3,7 +3,7 @@ import { z } from 'zod'; import prisma from '~/prisma'; import { catchErrors } from '../middlewares/errors'; import { type CustomError } from '~/types/error'; -import { type udis } from '@prisma/client'; +import { type udis as UdiType } from '@prisma/client'; const router = express.Router(); @@ -43,7 +43,7 @@ router.get( const longitude = parseFloat(lon as string); const latitude = parseFloat(lat as string); - const udi: udis = await prisma.$queryRaw` + const udis: Array = await prisma.$queryRaw` SELECT code_udi FROM public.udis WHERE ST_Within( @@ -52,7 +52,7 @@ router.get( ); `; - res.status(200).send({ ok: true, data: udi }); + res.status(200).send({ ok: true, data: udis[0] }); }, ), ); diff --git a/api-node/src/controllers/user.ts b/api-node/src/controllers/user.ts index 8ddd3ab8..c31b35bd 100644 --- a/api-node/src/controllers/user.ts +++ b/api-node/src/controllers/user.ts @@ -6,6 +6,7 @@ import { type CustomError } from '~/types/error'; import { type User } from '@prisma/client'; import { withUser } from '~/middlewares/auth.js'; import type { RequestWithUser } from '~/types/request'; +import { type udis as UdiType } from '@prisma/client'; const router = express.Router(); router.post( @@ -59,6 +60,12 @@ router.put( udi: z.string().optional(), push_notif_token: z.string().optional(), favorite_indicator: z.string().optional(), + coordinates: z + .object({ + lat: z.number(), + lon: z.number(), + }) + .optional(), notification_preference: z.array(z.string()).optional(), }).parse(req.body); } catch (zodError) { @@ -93,6 +100,25 @@ router.put( if (bodyHasProperty('udi')) { updatedUser.udi = req.body.udi; } + if (bodyHasProperty('coordinates')) { + if (req.body.coordinates.lat && req.body.coordinates.lon) { + const longitude = parseFloat(req.body.coordinates.lon); + const latitude = parseFloat(req.body.coordinates.lat); + + const udis: Array = await prisma.$queryRaw` + SELECT code_udi + FROM public.udis + WHERE ST_Within( + ST_SetSRID(ST_MakePoint(${longitude}, ${latitude}), 4326), + wkb_geometry + ); + `; + + if (udis?.length) { + updatedUser.udi = udis[0].code_udi; + } + } + } if (bodyHasProperty('push_notif_token')) { updatedUser.push_notif_token = req.body.push_notif_token; } diff --git a/api-node/src/getters/drinking_water.ts b/api-node/src/getters/drinking_water.ts index 33fe8fbf..cbbbfde7 100644 --- a/api-node/src/getters/drinking_water.ts +++ b/api-node/src/getters/drinking_water.ts @@ -85,8 +85,9 @@ async function getDrinkingWaterFromUdi({ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion recommendations: [drinkingWater.conclusion_conformite_prelevement!], }, - values: ((drinkingWater.all_tests_results ?? []) as Prisma.JsonArray)?.map( - (jsonValue) => { + values: ((drinkingWater.all_tests_results ?? []) as Prisma.JsonArray) + ?.filter((_, index) => index < 10) + .map((jsonValue) => { const test_result = jsonValue as unknown as ExtendedShortPrelevementResult; return { @@ -99,14 +100,13 @@ async function getDrinkingWaterFromUdi({ bacteriological: checkPrelevementConformityBacteriological(test_result), }, - drinkingWaterMetadata: { + drinkingWater: { parameters_count: test_result.parameters_count, prelevement_code: test_result.code_prelevement, prelevement_date: test_result.date_prelevement, }, }; - }, - ), + }), diffusion_date: dayjs(drinkingWater.diffusion_date).format('YYYY-MM-DD'), validity_start: dayjs(drinkingWater.diffusion_date).format('YYYY-MM-DD'), validity_end: 'N/A', diff --git a/api-node/src/getters/indicators_list.ts b/api-node/src/getters/indicators_list.ts index aeb3a13f..8f63cb7e 100644 --- a/api-node/src/getters/indicators_list.ts +++ b/api-node/src/getters/indicators_list.ts @@ -37,7 +37,6 @@ const indicatorsObject: Record = { slug: IndicatorsSlugEnum.bathing_water, }, [IndicatorsSlugEnum.drinking_water]: { - active: false, name: 'Eau du robinet', long_name: "La qualité de l'eau du robinet", short_name: 'Eau du robinet',