Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 1708-feat-instruction-ajoute-la-possibilite-de-voir-les-prochaines-etapes
  • a11y-ci
  • chore-image-snap
  • daily-check-phases
  • master
  • notifications
  • preprod
  • prod
  • prs-exploitant
  • try-better-perfs
  • vpn_rie
  • v0.1.0
  • v0.10.0
  • v0.100.0
  • v0.101.0
  • v0.102.0
  • v0.103.0
  • v0.104.0
  • v0.105.0
  • v0.106.0
  • v0.107.0
  • v0.108.0
  • v0.109.0
  • v0.11.0
  • v0.110.0
  • v0.111.0
  • v0.112.0
  • v0.113.0
  • v0.114.0
  • v0.115.0
  • v0.116.0
  • v0.117.0
  • v0.118.0
  • v0.119.0
  • v0.12.0
  • v0.12.1
  • v0.120.0
  • v0.13.0
  • v0.14.0
  • v0.15.0
  • v0.16.0
  • v0.17.0
  • v0.18.0
  • v0.19.0
  • v0.2.0
  • v0.2.1
  • v0.20.0
  • v0.21.0
  • v0.22.0
  • v0.23.0
  • v0.24.0
  • v0.24.1
  • v0.24.10
  • v0.24.11
  • v0.24.12
  • v0.24.13
  • v0.24.14
  • v0.24.15
  • v0.24.16
  • v0.24.17
  • v0.24.18
  • v0.24.19
  • v0.24.2
  • v0.24.20
  • v0.24.21
  • v0.24.22
  • v0.24.23
  • v0.24.24
  • v0.24.25
  • v0.24.26
  • v0.24.27
  • v0.24.28
  • v0.24.29
  • v0.24.3
  • v0.24.30
  • v0.24.31
  • v0.24.32
  • v0.24.33
  • v0.24.34
  • v0.24.35
  • v0.24.36
  • v0.24.37
  • v0.24.38
  • v0.24.39
  • v0.24.4
  • v0.24.40
  • v0.24.41
  • v0.24.42
  • v0.24.43
  • v0.24.44
  • v0.24.45
  • v0.24.46
  • v0.24.47
  • v0.24.48
  • v0.24.49
  • v0.24.5
  • v0.24.50
  • v0.24.51
  • v0.24.52
  • v0.24.53
  • v0.24.54
  • v0.24.55
  • v0.24.56
  • v0.24.57
  • v0.24.58
  • v0.24.59
  • v0.24.6
  • v0.24.60
  • v0.24.61
  • v0.24.62
  • v0.24.63
111 results

Target

Select target project
  • pub/pnm-public/camino
1 result
Select Git revision
  • 1708-feat-instruction-ajoute-la-possibilite-de-voir-les-prochaines-etapes
  • a11y-ci
  • chore-image-snap
  • daily-check-phases
  • master
  • notifications
  • preprod
  • prod
  • prs-exploitant
  • try-better-perfs
  • vpn_rie
  • v0.1.0
  • v0.10.0
  • v0.100.0
  • v0.101.0
  • v0.102.0
  • v0.103.0
  • v0.104.0
  • v0.105.0
  • v0.106.0
  • v0.107.0
  • v0.108.0
  • v0.109.0
  • v0.11.0
  • v0.110.0
  • v0.111.0
  • v0.112.0
  • v0.113.0
  • v0.114.0
  • v0.115.0
  • v0.116.0
  • v0.117.0
  • v0.118.0
  • v0.119.0
  • v0.12.0
  • v0.12.1
  • v0.120.0
  • v0.13.0
  • v0.14.0
  • v0.15.0
  • v0.16.0
  • v0.17.0
  • v0.18.0
  • v0.19.0
  • v0.2.0
  • v0.2.1
  • v0.20.0
  • v0.21.0
  • v0.22.0
  • v0.23.0
  • v0.24.0
  • v0.24.1
  • v0.24.10
  • v0.24.11
  • v0.24.12
  • v0.24.13
  • v0.24.14
  • v0.24.15
  • v0.24.16
  • v0.24.17
  • v0.24.18
  • v0.24.19
  • v0.24.2
  • v0.24.20
  • v0.24.21
  • v0.24.22
  • v0.24.23
  • v0.24.24
  • v0.24.25
  • v0.24.26
  • v0.24.27
  • v0.24.28
  • v0.24.29
  • v0.24.3
  • v0.24.30
  • v0.24.31
  • v0.24.32
  • v0.24.33
  • v0.24.34
  • v0.24.35
  • v0.24.36
  • v0.24.37
  • v0.24.38
  • v0.24.39
  • v0.24.4
  • v0.24.40
  • v0.24.41
  • v0.24.42
  • v0.24.43
  • v0.24.44
  • v0.24.45
  • v0.24.46
  • v0.24.47
  • v0.24.48
  • v0.24.49
  • v0.24.5
  • v0.24.50
  • v0.24.51
  • v0.24.52
  • v0.24.53
  • v0.24.54
  • v0.24.55
  • v0.24.56
  • v0.24.57
  • v0.24.58
  • v0.24.59
  • v0.24.6
  • v0.24.60
  • v0.24.61
  • v0.24.62
  • v0.24.63
111 results
Show changes
Commits on Source (13)
Showing
with 17153 additions and 13027 deletions
......@@ -14,4 +14,4 @@ COPY Makefile /app/Makefile
RUN CI=true make install
RUN mkdir /app/packages/api/node_modules /app/packages/ui/node_modules /app/packages/common/node_modules || true
RUN npx playwright@1.49.0 install --with-deps chromium
RUN npx playwright@1.50.1 install --with-deps chromium
......@@ -67,12 +67,12 @@ entity "**entreprises_etablissements**" {
}
entity "**etape_avis**" {
+ ""id"": //character varying(255) [PK]//
--
*""id"": //character varying(255) //
*""avis_type_id"": //character varying(255) //
*""avis_statut_id"": //character varying(255) //
*""avis_visibility_id"": //character varying(255) //
*""etape_id"": //character varying(255) //
*""etape_id"": //character varying(128) [FK]//
*""description"": //text //
*""date"": //character varying(10) //
""largeobject_id"": //oid //
......@@ -82,7 +82,7 @@ entity "**etapes_documents**" {
+ ""id"": //character varying(255) [PK]//
--
*""etape_document_type_id"": //character varying(3) //
*""etape_id"": //character varying(255) [FK]//
*""etape_id"": //character varying(128) [FK]//
""description"": //character varying(1024) //
*""public_lecture"": //boolean //
*""entreprises_lecture"": //boolean //
......@@ -129,14 +129,6 @@ entity "**logs**" {
*""utilisateur_id"": //character varying(255) [FK]//
}
entity "**perimetre_reference**" {
+ ""titre_etape_id"": //character varying(255) [PK][FK]//
+ ""geo_systeme"": //character varying(255) [PK]//
--
""opposable"": //boolean //
""geojson_perimetre"": //jsonb //
}
entity "**sdom_zones_postgis**" {
+ ""id"": //character varying(30) [PK]//
--
......@@ -173,8 +165,8 @@ entity "**titres**" {
}
entity "**titres__titres**" {
+ ""titre_from_id"": //character varying(255) [PK][FK]//
+ ""titre_to_id"": //character varying(255) [PK][FK]//
+ ""titre_from_id"": //character varying(128) [PK][FK]//
+ ""titre_to_id"": //character varying(128) [PK][FK]//
--
}
......@@ -182,7 +174,7 @@ entity "**titres_activites**" {
+ ""id"": //character varying(255) [PK]//
--
""titre_id"": //character varying(128) [FK]//
""utilisateur_id"": //character varying(128) [FK]//
""utilisateur_id"": //character varying(255) [FK]//
*""date"": //character varying(10) //
""date_saisie"": //character varying(10) //
""contenu"": //jsonb //
......@@ -245,7 +237,10 @@ entity "**titres_etapes**" {
*""amodiataire_ids"": //jsonb //
*""is_brouillon"": //boolean //
*""note"": //jsonb //
""demarche_id_en_concurrence"": //character varying [FK]//
""demarche_id_en_concurrence"": //character varying(128) [FK]//
*""etape_fondamentale_id"": //character varying(128) [FK]//
*""demarche_ids_consentement"": //jsonb //
*""departements"": //jsonb //
}
entity "**titres_etapes_entreprises_documents**" {
......@@ -271,13 +266,13 @@ entity "**utilisateurs**" {
entity "**utilisateurs__entreprises**" {
--
""utilisateur_id"": //character varying(64) [FK]//
""utilisateur_id"": //character varying(255) [FK]//
""entreprise_id"": //character varying(64) [FK]//
}
entity "**utilisateurs__titres**" {
+ ""utilisateur_id"": //character varying(255) [PK][FK]//
+ ""titre_id"": //character varying(255) [PK][FK]//
+ ""titre_id"": //character varying(128) [PK][FK]//
--
}
......@@ -287,14 +282,14 @@ entity "**utilisateurs__titres**" {
"**entreprises_etablissements**" }-- "**entreprises**"
"**etape_avis**" }-- "**titres_etapes**"
"**etapes_documents**" }-- "**titres_etapes**"
"**journaux**" }-- "**titres**"
"**logs**" }-- "**utilisateurs**"
"**perimetre_reference**" }-- "**titres_etapes**"
"**titres__titres**" }-- "**titres**"
"**titres__titres**" }-- "**titres**"
......@@ -311,6 +306,8 @@ entity "**utilisateurs__titres**" {
"**titres_etapes**" }-- "**titres_demarches**"
"**titres_etapes**" }-- "**titres_etapes**"
"**titres_etapes**" }-- "**titres_demarches**"
"**titres_etapes_entreprises_documents**" }-- "**entreprises_documents**"
......
Source diff could not be displayed: it is too large. Options to address this: view the blob.
This diff is collapsed.
......@@ -44,13 +44,13 @@
]
},
"devDependencies": {
"@semantic-release/gitlab": "^13.2.3",
"@semantic-release/gitlab": "^13.2.4",
"@types/react": "file:stub/types__react",
"husky": "^9.1.7",
"lint-staged": "^15.2.10",
"semantic-release": "^24.2.0",
"typescript": "^5.7.2",
"vue": "^3.5.4"
"lint-staged": "^15.4.3",
"semantic-release": "^24.2.2",
"typescript": "^5.7.3",
"vue": "^3.5.13"
},
"release": {
"branches": [
......
......@@ -135,4 +135,10 @@ export default [
],
},
},
{
files: ['**/migrations/*.ts'],
rules: {
'sql/no-unsafe-query': 'off',
},
},
]
......@@ -43,13 +43,13 @@
"modules esm": "On doit pouvoir migrer ts-node maintenant qu'on a supprimé express-graphql : https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c. mettre à jour express-jwt et graphql-upload"
},
"dependencies": {
"@graphql-tools/graphql-file-loader": "^8.0.6",
"@graphql-tools/load": "^8.0.7",
"@pgtyped/runtime": "^2.3.0",
"@sentry/node": "^8.42.0",
"@swc/core": "^1.10.1",
"@graphql-tools/graphql-file-loader": "^8.0.14",
"@graphql-tools/load": "^8.0.14",
"@pgtyped/runtime": "^2.4.2",
"@sentry/node": "^9.1.0",
"@swc/core": "^1.10.16",
"@tus/file-store": "^1.5.1",
"@tus/server": "^1.10.0",
"@tus/server": "^1.10.2",
"@types/basic-auth": "^1.1.8",
"@types/bcryptjs": "^2.4.6",
"@types/compression": "1.7.5",
......@@ -57,47 +57,46 @@
"@types/express": "^4.17.21",
"@types/express-serve-static-core": "^4.19.6",
"@types/graphql-type-json": "^0.3.5",
"@types/jsonwebtoken": "^9.0.7",
"@types/node": "^22.10.1",
"@types/pg": "^8.11.10",
"@types/jsonwebtoken": "^9.0.8",
"@types/node": "^22.13.2",
"@types/pg": "^8.11.11",
"@types/shpjs": "^3.4.7",
"basic-auth": "^2.0.1",
"bcryptjs": "^2.4.3",
"camino-common": "1.0.0",
"carbone": "^3.5.6",
"compression": "^1.7.5",
"compression": "^1.8.0",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"decimal.js": "^10.4.3",
"decimal.js": "^10.5.0",
"dotenv": "^16.4.7",
"effect": "^3.11.4",
"effect": "^3.12.11",
"express": "^4.21.2",
"express-jwt": "^8.4.1",
"express-rate-limit": "^7.4.1",
"graphql": "^16.9.0",
"express-jwt": "^8.5.1",
"express-rate-limit": "^7.5.0",
"graphql": "^16.10.0",
"graphql-fields": "^2.0.3",
"graphql-http": "^1.22.3",
"graphql-scalars": "^1.24.0",
"graphql-http": "^1.22.4",
"graphql-scalars": "^1.24.1",
"graphql-type-json": "^0.3.2",
"html-to-text": "^9.0.5",
"jsondiffpatch": "^0.6.0",
"jsonwebtoken": "^9.0.2",
"jszip": "^3.10.1",
"knex": "^3.1.0",
"node-mailjet": "^6.0.6",
"objection": "^3.1.5",
"pg": "^8.13.1",
"pg": "^8.13.3",
"pg-large-object": "^2.0.0",
"prettier": "^3.4.2",
"qs": "^6.13.1",
"prettier": "^3.5.1",
"qs": "^6.14.0",
"shpjs": "^6.1.0",
"stream-chain": "^3.1.0",
"stream-chain": "3.1.0",
"stream-json": "^1.9.1",
"ts-node": "^10.9.2",
"undici": "^6.21.0",
"undici": "^7.3.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
"xstate": "^5.19.0",
"zod": "^3.23.8",
"xstate": "^5.19.2",
"zod": "^3.24.2",
"zod-validation-error": "^3.4.0"
},
"devDependencies": {
......@@ -106,16 +105,16 @@
"@types/pg-large-object": "^2.0.7",
"@types/stream-json": "^1.7.8",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^8.17.0",
"@typescript-eslint/parser": "^8.17.0",
"@vitest/coverage-v8": "^2.1.8",
"eslint": "^9.16.0",
"eslint-config-prettier": "^9.1.0",
"@typescript-eslint/eslint-plugin": "^8.24.0",
"@typescript-eslint/parser": "^8.24.0",
"@vitest/coverage-v8": "^3.0.5",
"eslint": "^9.20.1",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-promise": "^7.2.1",
"eslint-plugin-sql": "^2.5.0",
"eslint-plugin-sql": "^3.2.1",
"supertest": "^7.0.0",
"typescript": "^5.7.2",
"vitest": "^2.0.5"
"typescript": "^5.7.3",
"vitest": "^3.0.5"
},
"prettier": {
"semi": false,
......
......@@ -95,6 +95,7 @@ const titreEtapeHeritageContenuBuild = (
(acc: { [elementId: string]: IHeritageElement }, element) => {
acc[element.id] = {
actif: !!titreEtapesFiltered.find(
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
e => e.id !== titreEtape.id && etapeSectionsDictionary[e.id] && (etapeSectionsDictionary[e.id]?.find(s => s.id === section.id && s.elements.find(el => el.id === element.id)) ?? false)
),
}
......@@ -107,7 +108,7 @@ const titreEtapeHeritageContenuBuild = (
return heritageContenu
}, {})
titreEtapesFiltered = titreEtapesFiltered.filter(e => etapeSectionsDictionary[e.id])
titreEtapesFiltered = titreEtapesFiltered.filter(e => isNotNullNorUndefined(etapeSectionsDictionary[e.id]))
const { contenu, heritageContenu } = titreEtapeHeritageContenuFind(titreEtapesFiltered, titreEtape, etapeSectionsDictionary)
......
......@@ -9,7 +9,7 @@ import { TitreTypeId } from 'camino-common/src/static/titresTypes'
import { DEMARCHES_TYPES_IDS } from 'camino-common/src/static/demarchesTypes'
import { ACTIVITES_STATUTS_IDS } from 'camino-common/src/static/activitesStatuts'
import { CaminoAnnee, getAnnee, toCaminoDate } from 'camino-common/src/date'
import { isNotNullNorUndefined, isNullOrUndefined } from 'camino-common/src/typescript-tools'
import { isNotNullNorUndefined, isNotNullNorUndefinedNorEmpty, isNullOrUndefined } from 'camino-common/src/typescript-tools'
import { getTitresModifiesByMonth } from '../../rest/journal.queries'
import { callAndExit } from '../../../tools/fp-tools'
......@@ -25,7 +25,7 @@ export const statistiquesGlobales = async (_: unknown, { pool }: Context): Promi
const demarches = titresActivites.filter(titreActivite => {
const dateSaisie = titreActivite.dateSaisie
return dateSaisie && dateSaisie.slice(0, 4) === new Date().getFullYear().toString()
return isNotNullNorUndefinedNorEmpty(dateSaisie) && dateSaisie.slice(0, 4) === new Date().getFullYear().toString()
}).length
return {
......@@ -57,7 +57,7 @@ export const titresSurfaceIndexBuild = (titres: ITitre[], annee: CaminoAnnee): T
for (const titre of titres) {
// titres dont le dernier octroi valide avec une phase valide débute cette année
const titreDemarcheOctroiValide = titre.demarches?.find(
demarche => demarche.typeId === DEMARCHES_TYPES_IDS.Octroi && demarche.demarcheDateDebut && getAnnee(demarche.demarcheDateDebut) === annee.toString()
demarche => demarche.typeId === DEMARCHES_TYPES_IDS.Octroi && isNotNullNorUndefined(demarche.demarcheDateDebut) && getAnnee(demarche.demarcheDateDebut) === annee.toString()
)
if (isNullOrUndefined(titreDemarcheOctroiValide)) {
......
......@@ -80,27 +80,18 @@ const titreEtapesPubliques: ITitreInsert = {
{
id: newEtapeId('titre-id-demarche-id-asc'),
typeId: 'asc',
ordre: 8,
titreDemarcheId: newDemarcheId('titre-id-demarche-id'),
statutId: 'fai',
date: toCaminoDate('2020-02-02'),
isBrouillon: ETAPE_IS_NOT_BROUILLON,
},
{
id: newEtapeId('titre-id-demarche-id-edm'),
typeId: 'edm',
ordre: 6,
titreDemarcheId: newDemarcheId('titre-id-demarche-id'),
statutId: 'acc',
statutId: 'fai',
date: toCaminoDate('2020-02-02'),
isBrouillon: ETAPE_IS_NOT_BROUILLON,
},
{
id: newEtapeId('titre-id-demarche-id-ede'),
typeId: 'ede',
id: newEtapeId('titre-id-demarche-id-exp'),
typeId: 'exp',
ordre: 5,
titreDemarcheId: newDemarcheId('titre-id-demarche-id'),
statutId: 'acc',
statutId: 'fav',
date: toCaminoDate('2020-02-02'),
isBrouillon: ETAPE_IS_NOT_BROUILLON,
},
......@@ -217,7 +208,7 @@ describe('titre', () => {
const res = await graphQLCall(dbPool, titreQuery, { id: 'titre-id' }, { role: 'admin', administrationId: ADMINISTRATION_IDS['DGTM - GUYANE'] })
expect(res.body.errors).toBe(undefined)
expect(res.body.data.titres.elements[0].demarches[0].etapes).toHaveLength(8)
expect(res.body.data.titres.elements[0].demarches[0].etapes).toHaveLength(7)
expect(
res.body.data.titres.elements[0].demarches[0].etapes.map(({ id }: { id: string }) => ({
id,
......@@ -226,8 +217,7 @@ describe('titre', () => {
expect.arrayContaining([
{ id: 'titre-id-demarche-id-asc' },
{ id: 'titre-id-demarche-id-dpu' },
{ id: 'titre-id-demarche-id-ede' },
{ id: 'titre-id-demarche-id-edm' },
{ id: 'titre-id-demarche-id-exp' },
{ id: 'titre-id-demarche-id-pfc' },
{ id: 'titre-id-demarche-id-pfd' },
{ id: 'titre-id-demarche-id-vfc' },
......
......@@ -291,7 +291,7 @@ describe('etapeCreer', () => {
expect(res.statusCode, JSON.stringify(res.body)).toBe(HTTP_STATUS.OK)
})
test('ne peut pas créer une étape EDE sur un titre ARM en tant que DGTM (utilisateur admin)', async () => {
test('ne peut pas créer une étape Expertises sur un titre ARM en tant que ONF (utilisateur admin)', async () => {
const titreDemarcheId = await demarcheCreate()
const res = await restNewPostCall(
......@@ -300,11 +300,11 @@ describe('etapeCreer', () => {
{},
{
role: 'admin',
administrationId: ADMINISTRATION_IDS['DGTM - GUYANE'],
administrationId: ADMINISTRATION_IDS['OFFICE NATIONAL DES FORÊTS'],
},
{
typeId: 'ede',
statutId: 'fai',
typeId: ETAPES_TYPES.expertises,
statutId: ETAPES_STATUTS.FAVORABLE,
titreDemarcheId,
date: toCaminoDate('2018-01-01'),
...blankEtapeProps,
......@@ -317,12 +317,12 @@ describe('etapeCreer', () => {
}
)
expect(res.statusCode).toBe(HTTP_STATUS.BAD_REQUEST)
expect(res.statusCode).toBe(HTTP_STATUS.NOT_FOUND)
expect(res.body).toMatchInlineSnapshot(`
{
"detail": "les étapes de la démarche TDE ne sont pas valides",
"message": "l'étape n'est pas valide",
"status": 400,
"detail": "L'utilisateur n'a pas accès à la démarche",
"message": "la démarche n'existe pas",
"status": 404,
}
`)
})
......@@ -331,8 +331,8 @@ describe('etapeCreer', () => {
const titreDemarcheId = await demarcheCreate()
const res = await restNewPostCall(dbPool, '/rest/etapes', {}, userSuper, {
typeId: 'ede',
statutId: 'fav',
typeId: ETAPES_TYPES.expertises,
statutId: ETAPES_STATUTS.FAVORABLE,
titreDemarcheId,
date: toCaminoDate('2018-01-01'),
...blankEtapeProps,
......
......@@ -21,6 +21,7 @@ import { etapeCreate } from './rest-test-utils'
import { insertTitreGraph, ITitreInsert, multiPolygonWith4Points } from '../../../tests/integration-test-helper'
import { ETAPES_TYPES } from 'camino-common/src/static/etapesTypes'
import { DOCUMENTS_TYPES_IDS } from 'camino-common/src/static/documentsTypes'
import { ETAPES_STATUTS } from 'camino-common/src/static/etapesStatuts'
vi.mock('../../tools/dir-create', () => ({
__esModule: true,
......@@ -546,8 +547,8 @@ describe('etapeModifier', () => {
expect(putRes.statusCode, JSON.stringify(putRes.body)).toBe(HTTP_STATUS.OK)
})
test('ne peut pas modifier une étape EDE sur un titre ARM en tant que PTMG (utilisateur admin)', async () => {
const { titreDemarcheId, titreEtapeId } = await etapeCreate('ede')
test('ne peut pas modifier une étape Expertises sur un titre ARM en tant que PTMG (utilisateur admin)', async () => {
const { titreDemarcheId, titreEtapeId } = await etapeCreate(ETAPES_TYPES.expertises)
const res = await restNewPutCall(
dbPool,
'/rest/etapes',
......@@ -558,8 +559,8 @@ describe('etapeModifier', () => {
},
{
id: titreEtapeId,
typeId: 'ede',
statutId: 'fai',
typeId: ETAPES_TYPES.expertises,
statutId: ETAPES_STATUTS.FAVORABLE,
titreDemarcheId,
date: caminoDateValidator.parse('2018-01-01'),
duree: null,
......
......@@ -159,7 +159,7 @@ const getTitreDates = (titre: Pick<ITitre, 'demarches'>): { dateDebut: CaminoDat
return {
dateDebut: sortedDemarches.find(demarche => !!demarche.demarcheDateDebut)?.demarcheDateDebut ?? null,
dateFin: sortedDemarches.reverse().find(demarche => demarche.demarcheDateDebut)?.demarcheDateFin ?? null,
dateFin: sortedDemarches.reverse().find(demarche => isNotNullNorUndefined(demarche.demarcheDateDebut))?.demarcheDateFin ?? null,
dateDemande: titreDateDemandeFind(sortedDemarches),
}
}
......
......@@ -165,7 +165,7 @@ C;Point éç;-52.55;4.24113309117193`
mkdirSync(dir, { recursive: true })
writeFileSync(
`${dir}/${fileName}`,
`nom;description;longitude;latitude
` nom ;description;longitude;latitude
A;;-52,54;4,22269896902571
B;;-52,55;4,22438936251509
C;Point éç;-52,55;4,24113309117193`
......@@ -178,9 +178,54 @@ C;Point éç;-52,55;4,24113309117193`
}
const tested = await restNewPostCall(dbPool, '/rest/geojson/import/:geoSystemeId', { geoSystemeId: GEO_SYSTEME_IDS.WGS84 }, userSuper, body)
expect(tested.statusCode).toBe(HTTP_STATUS.OK)
expect(tested.statusCode, JSON.stringify(tested.body)).toBe(HTTP_STATUS.OK)
expect(tested.body).toMatchSnapshot()
})
test('csv valide avec des virgules', async () => {
const fileName = `existing_temp_file_${idGenerate()}.csv`
mkdirSync(dir, { recursive: true })
writeFileSync(
`${dir}/${fileName}`,
`nom,description,longitude,latitude
A,,-52.54,4.22269896902571
B,,-52.55,4.22438936251509
C,Point éç,-52.55,4.24113309117193`
)
const body: GeojsonImportBody = {
titreSlug: titreSlugValidator.parse('titre-slug'),
titreTypeId: 'arm',
tempDocumentName: tempDocumentNameValidator.parse(fileName),
fileType: 'csv',
}
const tested = await restNewPostCall(dbPool, '/rest/geojson/import/:geoSystemeId', { geoSystemeId: GEO_SYSTEME_IDS.WGS84 }, userSuper, body)
expect(tested.body).toMatchInlineSnapshot(`
{
"detail": "Seuls les séparateurs ';' sont acceptés",
"message": "Le séparateur est probablement incorrect",
"status": 400,
}
`)
})
test('csv valide mais sans contenu', async () => {
const fileName = `existing_temp_file_${idGenerate()}.csv`
mkdirSync(dir, { recursive: true })
writeFileSync(`${dir}/${fileName}`, `nom,description,longitude,latitude`)
const body: GeojsonImportBody = {
titreSlug: titreSlugValidator.parse('titre-slug'),
titreTypeId: 'arm',
tempDocumentName: tempDocumentNameValidator.parse(fileName),
fileType: 'csv',
}
const tested = await restNewPostCall(dbPool, '/rest/geojson/import/:geoSystemeId', { geoSystemeId: GEO_SYSTEME_IDS.WGS84 }, userSuper, body)
expect(tested.body).toMatchInlineSnapshot(`
{
"message": "Le CSV ne contient aucun élément",
"status": 400,
}
`)
})
test('fichier valide geojson polygon', async () => {
const feature: FeatureCollectionPolygon = {
type: 'FeatureCollection',
......@@ -1474,7 +1519,7 @@ B;Point B;1063526.397924559889361;6867885.978687250986695;12,12;captage`
}
const tested = await restNewPostCall(dbPool, '/rest/geojson_forages/import/:geoSystemeId', { geoSystemeId: GEO_SYSTEME_IDS['RGFG95 / UTM zone 22N'] }, userSuper, body)
expect(tested.statusCode).toBe(HTTP_STATUS.OK)
expect(tested.statusCode, JSON.stringify(tested.body)).toBe(HTTP_STATUS.OK)
expect(tested.body).toMatchSnapshot()
const testedWithError = await restNewPostCall(dbPool, '/rest/geojson_forages/import/:geoSystemeId', { geoSystemeId: GEO_SYSTEME_IDS.WGS84 }, userSuper, body)
......
......@@ -41,7 +41,7 @@ import {
import { join } from 'node:path'
import { readFileSync } from 'node:fs'
import { parseShp } from 'shpjs'
import { isNotNullNorUndefined, isNullOrUndefined, memoize } from 'camino-common/src/typescript-tools'
import { isNotNullNorUndefined, isNotNullNorUndefinedNorEmpty, isNullOrUndefined, memoize } from 'camino-common/src/typescript-tools'
import { SDOMZoneId } from 'camino-common/src/static/sdom'
import { TitreSlug } from 'camino-common/src/validators/titres'
import { canReadEtape } from './permissions/etapes'
......@@ -157,7 +157,7 @@ const csvCommonValidator = z
if ('Nom du point' in value) {
value.nom = value['Nom du point']
}
Object.keys(value).forEach(k => (value[k.toLowerCase()] = value[k]))
Object.keys(value).forEach(k => (value[k.toLowerCase().trim()] = value[k]))
return value
})
......@@ -186,7 +186,6 @@ type GeojsonImportErrorMessages =
| EffectDbQueryAndValidateErrors
| typeof ouvertureGeoJSONError
| typeof ouvertureShapeError
| typeof ouvertureCsvError
| typeof importCsvRestrictionError
| typeof recuperationInfoCsvError
| typeof extractionGeoJSONError
......@@ -194,6 +193,8 @@ type GeojsonImportErrorMessages =
| GetGeojsonByGeoSystemeIdErrorMessages
| GetGeojsonInformationErrorMessages
| ConvertPointsErrors
| FileNameToCsvErrors
export const geojsonImport: RestNewPostCall<'/rest/geojson/import/:geoSystemeId'> = (rootPipe): Effect.Effect<GeojsonInformations, CaminoApiError<GeojsonImportErrorMessages>> => {
return rootPipe.pipe(
Effect.let('pathFrom', ({ body }) => join(process.cwd(), `/files/tmp/${body.tempDocumentName}`)),
......@@ -373,6 +374,8 @@ export const geojsonImport: RestNewPostCall<'/rest/geojson/import/:geoSystemeId'
'La liste des points est vide',
'Le nombre de points est invalide',
'Problème de Système géographique (SRID)',
'Le CSV ne contient aucun élément',
'Le séparateur est probablement incorrect',
() => ({ ...caminoError, status: HTTP_STATUS.BAD_REQUEST })
),
Match.exhaustive
......@@ -417,7 +420,10 @@ const readIsoOrUTF8FileSync = (path: string): string => {
}
}
const fileNameToCsv = (pathFrom: string): Effect.Effect<unknown[], CaminoError<typeof ouvertureCsvError>> => {
const csvVideError = 'Le CSV ne contient aucun élément' as const
const mauvaisSeparateurCsvError = 'Le séparateur est probablement incorrect' as const
type FileNameToCsvErrors = typeof ouvertureCsvError | typeof mauvaisSeparateurCsvError | typeof csvVideError
const fileNameToCsv = (pathFrom: string): Effect.Effect<unknown[], CaminoError<FileNameToCsvErrors>> => {
return Effect.try({
try: () => {
const fileContent = readIsoOrUTF8FileSync(pathFrom)
......@@ -428,11 +434,22 @@ const fileNameToCsv = (pathFrom: string): Effect.Effect<unknown[], CaminoError<t
}
const sheet1 = result.Sheets[result.SheetNames[0]]
return xlsx.utils.sheet_to_json(sheet1, { raw: true })
},
catch: e => ({ message: ouvertureCsvError, extra: e }),
})
}).pipe(
Effect.filterOrFail(
result => isNotNullNorUndefinedNorEmpty(result),
() => ({ message: csvVideError })
),
Effect.filterOrFail(
result => {
const firstValue = result[0]
return typeof firstValue === 'object' && isNotNullNorUndefined(firstValue) && Object.keys(firstValue).length >= 2
},
() => ({ message: mauvaisSeparateurCsvError, detail: "Seuls les séparateurs ';' sont acceptés" })
)
)
}
const accesInterditError = 'Accès interdit' as const
......@@ -485,7 +502,7 @@ export const geojsonImportPoints: RestNewPostCall<'/rest/geojson_points/import/:
)
}
type GeosjsonImportForagesErrorMessages = ZodUnparseable | EffectDbQueryAndValidateErrors | typeof ouvertureCsvError | typeof ouvertureShapeError | typeof ouvertureGeoJSONError | ConvertPointsErrors
type GeosjsonImportForagesErrorMessages = ZodUnparseable | EffectDbQueryAndValidateErrors | typeof ouvertureShapeError | typeof ouvertureGeoJSONError | ConvertPointsErrors | FileNameToCsvErrors
export const geojsonImportForages: RestNewPostCall<'/rest/geojson_forages/import/:geoSystemeId'> = (
rootPipe
): Effect.Effect<GeojsonImportForagesResponse, CaminoApiError<GeosjsonImportForagesErrorMessages>> => {
......@@ -560,6 +577,8 @@ export const geojsonImportForages: RestNewPostCall<'/rest/geojson_forages/import
'La liste des points est vide',
'Le nombre de points est invalide',
'Problème de Système géographique (SRID)',
'Le CSV ne contient aucun élément',
'Le séparateur est probablement incorrect',
() => ({ ...caminoError, status: HTTP_STATUS.BAD_REQUEST })
),
Match.exhaustive
......
......@@ -4,6 +4,7 @@ import { CanReadDemarche } from './demarches'
import { testBlankUser } from 'camino-common/src/tests-utils'
import { isAssociee, isGestionnaire } from 'camino-common/src/static/administrationsTitresTypes'
import { entrepriseIdValidator } from 'camino-common/src/entreprise'
import { ETAPES_TYPES } from 'camino-common/src/static/etapesTypes'
const shouldNotBeCalled = () => Promise.reject(new Error('should not be called'))
......@@ -29,7 +30,7 @@ describe('canReadEtape', () => {
() => Promise.resolve(titreTypeId),
() => Promise.resolve([]),
shouldNotBeCalled,
'ede',
ETAPES_TYPES.expertises,
demarche
)
).toBe(false)
......@@ -40,7 +41,7 @@ describe('canReadEtape', () => {
() => Promise.resolve(titreTypeId),
() => Promise.resolve([]),
shouldNotBeCalled,
'ede',
ETAPES_TYPES.expertises,
demarche
)
).toBe(true)
......
......@@ -20,7 +20,7 @@ export const evolutionTitres = async (pool: Pool, titreTypeTypeId: TitreTypeType
}
const demarcheOctroiTypeIds = [DEMARCHES_TYPES_IDS.Octroi, DEMARCHES_TYPES_IDS.Prolongation, DEMARCHES_TYPES_IDS.Prolongation1, DEMARCHES_TYPES_IDS.Prolongation2]
const titreTypeId = toTitreTypeId(titreTypeTypeId, DOMAINES_IDS.METAUX)
const etapesTypesDecisionRefus = [ETAPES_TYPES.decisionImplicite, ETAPES_TYPES.decisionDeLAutoriteAdministrative, ETAPES_TYPES.decisionDuJugeAdministratif]
const etapesTypesDecisionRefus = [ETAPES_TYPES.decisionDeLAutoriteAdministrative, ETAPES_TYPES.decisionDuJugeAdministratif]
// conversion 1 km² = 100 ha
const [depot, octroi, refus, surface] = await Promise.all([
......
......@@ -31,7 +31,7 @@ import { EffectDbQueryAndValidateErrors } from '../../pg-database'
import { CaminoMachines, machineFind } from '../../business/rules-demarches/machines'
import { demarcheEnregistrementDemandeDateFind } from 'camino-common/src/demarche'
const etapesAMasquer = [ETAPES_TYPES.classementSansSuite, ETAPES_TYPES.desistementDuDemandeur, ETAPES_TYPES.decisionImplicite, ETAPES_TYPES.demandeDeComplements_RecevabiliteDeLaDemande_]
const etapesAMasquer = [ETAPES_TYPES.classementSansSuite, ETAPES_TYPES.desistementDuDemandeur, ETAPES_TYPES.demandeDeComplements_RecevabiliteDeLaDemande_]
export const titresAdministrations =
(_pool: Pool) =>
......
......@@ -2,6 +2,7 @@ import { isNotNullNorUndefined, isNotNullNorUndefinedNorEmpty } from 'camino-com
import { Index, IEntrepriseEtablissement, IEntreprise } from '../types'
export const dailySummaryMarker = 'tâches exécutées:' as const
export const logsUpdate = ({
heritageWithUnknownEtapes,
etapesCompletesErreurs,
tdeErreurs,
demarcheDefinitionsErreurs,
......@@ -29,6 +30,7 @@ export const logsUpdate = ({
etablissementsUpdated,
etablissementsDeleted,
}: {
heritageWithUnknownEtapes?: unknown[]
etapesCompletesErreurs?: { surTitreValide: string[]; autre: string[]; etapesRecentes: string[] }
tdeErreurs?: number
demarcheDefinitionsErreurs?: number
......@@ -72,6 +74,9 @@ export const logsUpdate = ({
}
}
if (isNotNullNorUndefinedNorEmpty(heritageWithUnknownEtapes)) {
console.error(`${heritageWithUnknownEtapes.length} heritage de contenu qui pointe sur des étapes non existantes`)
}
if (isNotNullNorUndefined(tdeErreurs) && tdeErreurs > 0) {
console.warn(`${tdeErreurs} erreurs TDE`)
}
......
......@@ -10,7 +10,7 @@ import { titresPublicUpdate } from './processes/titres-public-update'
import { titresPropsEtapesIdsUpdate } from './processes/titres-props-etapes-ids-update'
import { titresStatutIdsUpdate } from './processes/titres-statut-ids-update'
import { titresEtapesHeritagePropsUpdate } from './processes/titres-etapes-heritage-props-update'
import { titresEtapesHeritageContenuUpdate } from './processes/titres-etapes-heritage-contenu-update'
import { checkEtapeInContenuHeritage, titresEtapesHeritageContenuUpdate } from './processes/titres-etapes-heritage-contenu-update'
import { titresActivitesPropsUpdate } from './processes/titres-activites-props-update'
import { titresSlugsUpdate } from './processes/titres-slugs-update'
import { logsUpdate } from './_logs-update'
......@@ -40,6 +40,7 @@ export const daily = async (pool: Pool): Promise<void> => {
const fondamentaleIdUpdated = await callAndExit(etapesFondamentaleIdUpdateForAll(pool))
const titresEtapesHeritagePropsUpdated = await titresEtapesHeritagePropsUpdate(userSuper)
const titresEtapesHeritageContenuUpdated = await titresEtapesHeritageContenuUpdate(pool, userSuper)
const heritageWithUnknownEtapes = await callAndExit(checkEtapeInContenuHeritage(pool))
const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate(pool)
const titresDemarchesOrdreUpdated = await titresDemarchesOrdreUpdate()
......@@ -62,6 +63,7 @@ export const daily = async (pool: Pool): Promise<void> => {
const etapesCompletesErreurs = await etapesCompletesCheck(pool)
logsUpdate({
heritageWithUnknownEtapes,
etapesCompletesErreurs: etapesCompletesErreurs,
tdeErreurs,
demarcheDefinitionsErreurs,
......