diff --git a/.github/workflows/nightly-publish.yml b/.github/workflows/nightly-publish.yml index 764389f6..cacea9d5 100644 --- a/.github/workflows/nightly-publish.yml +++ b/.github/workflows/nightly-publish.yml @@ -9,7 +9,17 @@ jobs: publish-to-data-gouv: strategy: matrix: - source: [hinaura, maine-et-loire, les-assembleurs, france-services, conseiller-numerique, francil-in, angers] + source: + [ + hinaura, + maine-et-loire, + les-assembleurs, + france-services, + france-tiers-lieux, + conseiller-numerique, + francil-in, + angers + ] runs-on: ubuntu-latest environment: production diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 421f92e1..ad5fe6f7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,17 @@ jobs: name: Publish to data.gouv strategy: matrix: - source: [hinaura, maine-et-loire, les-assembleurs, france-services, conseiller-numerique, francil-in, angers] + source: + [ + hinaura, + maine-et-loire, + les-assembleurs, + france-services, + france-tiers-lieux, + conseiller-numerique, + francil-in, + angers + ] runs-on: ubuntu-latest environment: production diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7cf9b88f..1197a300 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -52,7 +52,17 @@ jobs: publish-to-data-gouv: strategy: matrix: - source: [hinaura, maine-et-loire, les-assembleurs, france-services, conseiller-numerique, francil-in, angers] + source: + [ + hinaura, + maine-et-loire, + les-assembleurs, + france-services, + france-tiers-lieux, + conseiller-numerique, + francil-in, + angers + ] runs-on: ubuntu-latest environment: demo diff --git a/.gitignore b/.gitignore index 08a5b3e0..f7bc3c65 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ # Generated files /assets/output/ +/assets/input/france-tiers-lieux/france-tiers-lieux.json # Logs logs diff --git a/assets/input/france-tiers-lieux/france-tiers-lieux.config.json b/assets/input/france-tiers-lieux/france-tiers-lieux.config.json new file mode 100644 index 00000000..197f566d --- /dev/null +++ b/assets/input/france-tiers-lieux/france-tiers-lieux.config.json @@ -0,0 +1,236 @@ +{ + "id": { + "colonne": "_id.$id" + }, + "nom": { + "colonne": "name" + }, + "commune": { + "colonne": "address.addressLocality" + }, + "code_postal": { + "colonne": "address.postalCode" + }, + "adresse": { + "colonne": "address.streetAddress" + }, + "latitude": { + "colonne": "geo.latitude" + }, + "longitude": { + "colonne": "geo.longitude" + }, + "date_maj": { + "colonne": "updated" + }, + "presentation_resume": { + "colonne": "shortDescription" + }, + "presentation_detail": { + "colonne": "description" + }, + "services": [ + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": [ + "PC en libres accès", + "disposer d’équipements", + "bureaux privatifs", + "postes de travail", + "Atelier de Fabrication Numérique", + "Fablab", + "ordinateur", + "Espace Public Numérique", + "EPN" + ], + "cible": "Accéder à du matériel" + }, + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": [ + "PC en libres accès", + "disposer d’équipements", + "bureaux privatifs", + "postes de travail", + "Atelier de Fabrication Numérique", + "Fablab", + "Coworking", + "Espace Public Numérique", + "EPN" + ], + "cible": "Accéder à une connexion internet" + }, + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": ["PC en libres accès", "disposer d’équipements", "Espace Public Numérique", "EPN"], + "cible": "Prendre en main un ordinateur" + }, + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": ["smartphone", "Espace Public Numérique", "EPN"], + "cible": "Prendre en main un smartphone ou une tablette" + }, + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": [ + "apprentis", + "demandeurs d’emploi", + "personnes en reconversion", + "Atelier de Fabrication Numérique", + "Fablab", + "Lieu d'éducation populaire et nouvelles formes d'apprentissage", + "Formation", + "Transfert de savoir-faire", + "Éducation", + "étudiants", + "accompagnement à la scolarité", + "Espace Public Numérique", + "EPN" + ], + "cible": "Favoriser mon insertion professionnelle" + }, + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": ["création d’entreprise", "Coworking", "Incubateur", "Espace Public Numérique", "EPN"], + "cible": "Créer et développer mon entreprise" + }, + { + "colonnes": ["description", "tags", "shortDescription"], + "termes": [ + "création d’entreprise", + "Coworking", + "Incubateur", + "Espace Public Numérique", + "EPN", + "Atelier de Fabrication Numérique", + "Fablab" + ], + "cible": "Créer avec le numérique" + }, + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": ["échange des savoirs", "Médiation numérique", "Espace Public Numérique", "EPN"], + "cible": "Approfondir ma culture numérique" + }, + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": ["échange des savoirs", "Médiation numérique", "Espace Public Numérique", "EPN"], + "cible": "Promouvoir la citoyenneté numérique" + }, + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": ["échange des savoirs", "Médiation numérique", "Espace Public Numérique", "EPN"], + "cible": "Utiliser le numérique au quotidien" + }, + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": [ + "Accompagnement à la parentalité", + "parentalité", + "accompagnement à la scolarité", + "Espace Public Numérique", + "EPN" + ], + "cible": "Soutenir la parentalité et l'éducation avec le numérique" + }, + { + "colonnes": ["description", "tags"], + "termes": ["Espace Public Numérique", "EPN"], + "cible": "Devenir autonome dans les démarches administratives" + }, + { + "colonnes": ["description", "tags"], + "termes": ["Espace Public Numérique", "EPN"], + "cible": "Réaliser des démarches administratives avec un accompagnement" + }, + { + "colonnes": ["description", "tags"], + "termes": ["Espace Public Numérique", "EPN"], + "cible": "Accompagner les démarches de santé" + } + ], + "modalites_accompagnement": [ + { + "colonnes": ["description"], + "termes": ["ateliers collectifs", "Espace Public Numérique", "EPN"], + "cible": "Dans un atelier : j'apprends collectivement à utiliser le numérique" + }, + { + "colonnes": ["description"], + "termes": ["ateliers individuels", "Espace Public Numérique", "EPN"], + "cible": "Avec de l'aide : je suis accompagné seul dans l'usage du numérique" + } + ], + "publics_accueillis": [ + { + "colonnes": ["description", "shortDescription", "tags"], + "termes": [ + "jeunesse", + "accueillir des jeunes", + "toutes personnes", + "ouvert au grand public", + "Formation", + "Éducation", + "étudiants" + ], + "cible": "Jeunes (16-26 ans)" + }, + { + "colonnes": ["description", "tags", "shortDescription"], + "termes": ["toutes personnes", "Coworking", "Espace détente", "ouvert au grand public", "entreprises", "particuliers"], + "cible": "Adultes" + }, + { + "colonnes": ["description", "tags", "shortDescription"], + "termes": ["toutes personnes", "Espace enfants", "ouvert au grand public"], + "cible": "Familles/enfants" + }, + { + "colonnes": ["description", "shortDescription"], + "termes": ["toutes personnes", "ouvert au grand public"], + "cible": "Seniors (+ 65 ans)" + }, + { + "colonnes": ["description", "shortDescription"], + "termes": ["toutes personnes", "ouvert au grand public"], + "cible": "Déficience visuelle" + }, + { + "colonnes": ["description", "shortDescription"], + "termes": ["toutes personnes", "ouvert au grand public"], + "cible": "Handicaps psychiques : troubles psychiatriques donnant lieu à des atteintes comportementales" + }, + { + "colonnes": ["description", "shortDescription"], + "termes": ["toutes personnes", "ouvert au grand public"], + "cible": "Public langues étrangères" + }, + { + "colonnes": ["description", "shortDescription"], + "termes": ["toutes personnes", "ouvert au grand public"], + "cible": "Surdité" + }, + { + "colonnes": ["description", "shortDescription"], + "termes": ["toutes personnes", "accompagnons les femmes", "ouvert au grand public"], + "cible": "Uniquement femmes" + }, + { + "colonnes": ["description", "shortDescription"], + "termes": ["toutes personnes", "ouvert au grand public"], + "cible": "Handicaps mentaux : déficiences limitant les activités d'une personne" + }, + { + "colonnes": ["description", "shortDescription"], + "termes": ["toutes personnes", "ouvert au grand public"], + "cible": "Personnes en situation d'illettrisme" + } + ], + "conditions_acces": [ + { + "colonnes": ["description"], + "termes": ["disposition des adhérents"], + "cible": "Adhésion : L'accès au lieu et/ou à ses services nécessite d'y adhérer" + } + ] +} diff --git a/assets/input/francil-in/services.francil-in.md b/assets/input/francil-in/services.francil-in.md new file mode 100644 index 00000000..5d329c9a --- /dev/null +++ b/assets/input/francil-in/services.francil-in.md @@ -0,0 +1,156 @@ +# Liste des services Francil'in + +## La recherche d'un emploi +- 110: Panorama des plateformes de recherche d’emploi +- 111: Organiser sa recherche d'emploi +- 112: Découverte et usage de l’emploi Store +- 113: Utiliser les réseaux sociaux pour sa recherche d'emploi +- 114: Réalisation CV +- 115: Diffuser son CV en ligne +- 116: Découvrir et participer à des MOOCs + +## Les déclarations en ligne (E-admin) +- 201: Les paiements en ligne +- 202: Signer numériquement des documents administratifs +- 203: Pôle Emploi : faire ses déclarations en ligne +- 204: Déclarer ses revenus en ligne et découvertes des services proposés +- 205: Accéder à ses droits sociaux et les gérer en ligne (RSA…) +- 206: Ouvrir et gérer son dossier de retraite (CNAF/CARSAT) en ligne +- 207: Gérer son abonnement et ses factures d'électricité/gaz en ligne +- 208: Gérer ses droits d'assuré social en ligne/sur internet +- 209: Gérer ses droits et allocations (CAF...) en ligne/sur internet +- 210: Plateforme La Poste : envoyer et recevoir des courriers +- 211: Plateforme La Poste : utiliser le coffre-fort en ligne +- 212: Plateforme Ameli.fr : la sécurité sociale en ligne +- 213: Découvrir les services en ligne de l'enfance de votre commune +- 214: Plateforme France Connect + +## Les premiers pas sur internet et en informatique +- 301: Fonctionnement d’une box internet +- 302: Le smartphone : principes de fonctionnement +- 303: Poste informatique Windows +- 304: Poste informatique Mac OS +- 305: Poste informatique Linux +- 306: Internet : paramétrer un réseau wifi +- 307: Smartphones et Tablettes sous Androïd +- 308: Smartphone : Environnement IOS +- 309: Smartphone : Les applications clés +- 310: Smartphone : Les principaux gestes pour l'écran tactile +- 311: Smartphone : Les fonctionnalités de base +- 312: Smartphone : Télécharger une application sur les stores +- 313: Smartphone : Réglage et configuration de l'appareil +- 314: Gérer ses données : Sauvegardes locales (disques durs externes, clé USB) +- 315: Internet : fonctionnement des emails +- 316: Internet : fonctionnement des clients webmail +- 317: Internet : envoyer, recevoir, gérer ses emails +- 318: Transférer des fichiers volumineux +- 319: Internet : fonctionnement et outils de navigation web +- 320: Internet : comprendre une offre internet +- 321: Internet : comprendre les principes de fonctionnement +- 322: Internet : comprendre un réseau wifi +- 323: Gérer ses favoris de navigation +- 324: Effacer ses traces sur le web, protéger ses données personnelles +- 325: Découvrir les réseaux sociaux : définition, fonctionnement +- 326: Téléphonie : comprendre et comparer des offres mobiles +- 327: Facebook : Découverte +- 328: Twitter : Découverte +- 329: Instagram : Découverte +- 330: Pinterest : Découverte +- 331: Snapchat : Découverte +- 332: Ateliers Smartphone débutant +- 333: Atelier Ordinateur débutant +- 334: Atelier Email débutant +- 335: Atelier Internet débutant +- 336: Atelier Budget Internet et Numérique +- 337: Atelier Réseaux sociaux + +## L'utilisation des outils bureautiques +- 401: Traitement de texte : Découverte +- 402: Traitement de texte : Utilisation de base +- 403: Traitement de texte : Utilisation avancée +- 404: Tableur : Découverte +- 405: Tableur : Utilisation de base +- 406: Tableur : Utilisation avancée +- 407: Les solutions libres pour Les outils bureautiques +- 408: PAO : faire des présentations, des diaporamas + +## L'approfondissement du numérique +- 501: Composantes et facettes de l’identité numérique +- 502: Connaitre et gérer son identité numérique +- 503: Nettoyer son identité numérique +- 504: Les outils disponibles pour sécuriser ses usages numériques +- 505: Les biens communs : principes et enjeux +- 506: Le logiciel libre : principes et enjeux +- 507: Les licences libres +- 508: Les monnaies virtuelles +- 509: Big Data / Open Data : comprendre les données +- 510: Techniques de vérification de l’information +- 511: Neutralité du net : de quoi parle-t-on ? +- 512: Découvrir des alternatives libres et gratuits aux logiciels +- 513: Les outils libres pour la navigation Internet +- 514: Les outils libres pour gérer ses emails +- 515: Les alternatives à Google Drive +- 516: Les alternatives à Facebook +- 517: Panorama des objets connectés (Domotique, Sécurité, Santé) +- 518: Créer et paramétrer un compte Google +- 519: Organiser, explorer et partager des contenus numériques +- 520: Gérer ses données : Sauvegarde en ligne (dans le cloud) +- 521: Facebook : Approfondissement +- 522: Twitter : Approfondissement +- 523: Instagram : Approfondissement +- 524: Pinterest : Approfondissement +- 525: Organiser et partager sa veille + +## Des conseils sur la parentalité numérique +- 601: Etre parent à l'ère numérique : connaître les usages, jouer son rôle de parent +- 602: Panorama des usages numériques des adolescents +- 603: Les mécanismes excessifs ou addictifs liés au numérique +- 604: Les outils de protection de l’enfance +- 605: Comprendre les cultures numériques : les jeux vidéos +- 606: Suivre la scolarité de son enfant +- 607: Les conduites à risques et les bons usages du numérique +- 608: Outils numériques pour maîtriser sa consommation énergétique + +## L'utilisation d'outils créatifs +- 701: Panorama d’usages créatifs du numérique +- 702: Panorama de la création artistique numérique +- 703: Fablab : charte, valeurs et panorama des outils numériques +- 704: Fonctionnement des plateformes de musique et de film en ligne +- 705: Découvrir l’univers des jeux vidéos +- 706: Les paiements en ligne +- 707: Comprendre les cultures numériques : les jeux vidéos +- 708: Photo numérique : usages courants (prise de vue, réglages) +- 709: Classer, gérer et partager ses photos +- 710: Images : gérer ses photos en ligne +- 711: Images : retoucher ses photos +- 712: Découverte et utilisation imprimante 3D +- 713: Vidéo : découvrir le montage vidéo +- 714: Découverte et utilisation d'une découpeuse numérique +- 715: Modélisation 3D +- 716: Internet : déposer une annonce sur Le Bon Coin ou autre site de petites annonces +- 717: Utiliser et contribuer à Wikipedia +- 718: Découvrir et contribuer à OpenStreetMap +- 719: Utiliser des outils de cartographie +- 720: Services et plateformes de démocratie participative +- 721: Découvrir et expérimenter la programmation informatique (code) +- 722: Utiliser des cartes, capteurs et outils interactifs +- 723: Produire (Imp3D / robotique / FabLab) +- 724: Vos loisirs (son, vidéo, image) + +## Des usages professionnels sur informatique +- 801: Panorama des outils de webconférence +- 802: Panorama des outils de travail collaboratif +- 803: Marchés publics : panorama des plateformes +- 804: Panorama des plateformes d’économie collaborative +- 805: Principes et fonctionnement du cloud +- 806: Google Drive et solutions alternatives +- 807: Skype +- 808: Marchés publics : Signer numériquement ses réponses +- 809: PAO : publier des présentations / diaporamas en ligne +- 810: Savoir pitcher son projet en 5 minutes +- 811: Créer un site web avec WordPress +- 812: Créer, paramétrer et utiliser une liste de diffusion +- 813: Utilisation d'un emplacement de co-working +- 814: Découvrir les métiers du numérique +- 815: Découverte des outils de messagerie instantanée (tchat) +- 816: Panorama des outils du cloud diff --git a/package.json b/package.json index 3e180efb..a6fa5963 100644 --- a/package.json +++ b/package.json @@ -47,9 +47,11 @@ "start.data-inclusion": "ts-node src/data-inclusion/main.ts", "mednum": "ts-node src/index.ts", "transformer.angers": "ts-node src/index.ts transformer -n \"Angers\" -t \"Maine-et-Loire\" -s \"./assets/input/angers/angers.json\" -c \"./assets/input/angers/angers.config.json\" -o \"./assets/output/angers\"", + "fetch.france-tiers-lieux": "curl --request POST --url https://cartographie.francetierslieux.fr/co2/search/globalautocomplete --header 'Content-Type: application/x-www-form-urlencoded' --data 'searchType[]=organizations' --data indexStep= --data costumSlug=franceTierslieux > assets/input/france-tiers-lieux/france-tiers-lieux.json", "transformer.conseiller-numerique": "ts-node src/index.ts transformer -n \"Conseiller Numerique\" -t \"National\" -s \"https://api.conseiller-numerique.gouv.fr/permanences\" -c \"./assets/input/conseiller-numerique/conseiller-numerique.config.json\" -o \"./assets/output/conseiller-numerique\"", "transformer.france-services": "ts-node src/index.ts transformer -n \"France Services\" -t \"National\" -s \"https://www.data.gouv.fr/fr/datasets/r/afc3f97f-0ef5-429b-bf16-7b7876d27cd4\" -c \"./assets/input/france-services/france-services.config.json\" -o \"./assets/output/france-services\"", "transformer.francil-in": "ts-node src/index.ts transformer -n \"Francil-in\" -t \"Île-de-France\" -s \"https://data.francilin.fr/structures.geojson@features\" -c \"./assets/input/francil-in/francil-in.config.json\" -o \"./assets/output/francil-in\"", + "transformer.france-tiers-lieux": "yarn fetch.france-tiers-lieux && ts-node src/index.ts transformer -n \"France tiers-lieux\" -t \"National\" -s \"./assets/input/france-tiers-lieux/france-tiers-lieux.json@results\" -c \"./assets/input/france-tiers-lieux/france-tiers-lieux.config.json\" -o \"./assets/output/france-tiers-lieux\"", "transformer.hinaura": "ts-node src/index.ts transformer -n \"Hinaura\" -t \"Auvergne-Rhône-Alpes\" -s \"./assets/input/hinaura/hinaura.json\" -c \"./assets/input/hinaura/hinaura.config.json\" -o \"./assets/output/hinaura\"", "transformer.maine-et-loire": "ts-node src/index.ts transformer -n \"Département du Maine-et-Loire\" -t \"Maine-et-Loire\" -s \"./assets/input/maine-et-loire/maine-et-loire.json\" -c \"./assets/input/maine-et-loire/maine-et-loire.config.json\" -o \"./assets/output/maine-et-loire\"", "transformer.les-assembleurs": "ts-node src/index.ts transformer -n \"Les Assembleurs\" -t \"Hauts-de-France\" -s \"./assets/input/les-assembleurs/les-assembleurs.json\" -c \"./assets/input/les-assembleurs/les-assembleurs.config.json\" -o \"./assets/output/les-assembleurs\"", @@ -57,6 +59,7 @@ "publier.conseiller-numerique": "ts-node src/index.ts publier -z \"country:fr\" -m \"./assets/output/conseiller-numerique/publier.json\"", "publier.france-services": "ts-node src/index.ts publier -z \"country:fr\" -m \"./assets/output/france-services/publier.json\"", "publier.francil-in": "ts-node src/index.ts publier -z \"fr:region:11\" -m \"./assets/output/francil-in/publier.json\"", + "publier.france-tiers-lieux": "ts-node src/index.ts publier -z \"country:fr\" -m \"./assets/output/france-tiers-lieux/publier.json\"", "publier.hinaura": "ts-node src/index.ts publier -z \"fr:region:84\" -m \"./assets/output/hinaura/publier.json\"", "publier.maine-et-loire": "ts-node src/index.ts publier -z \"fr:departement:49\" -m \"./assets/output/maine-et-loire/publier.json\"", "publier.les-assembleurs": "ts-node src/index.ts publier -z \"fr:region:32\" -m \"./assets/output/les-assembleurs/publier.json\"" diff --git a/src/transformer/cli/action/transformer.action.ts b/src/transformer/cli/action/transformer.action.ts index af1cb34a..e00a50cb 100644 --- a/src/transformer/cli/action/transformer.action.ts +++ b/src/transformer/cli/action/transformer.action.ts @@ -15,21 +15,24 @@ const flatten = require('flat'); const REPORT: Report = Report(); -const fromJson = (response: AxiosResponse, key?: string): T => - key != null && response.data[key] != null ? response.data[key] : response.data; +const fromJson = (response: Record, key?: string): T[] => + key == null ? Object.values(response) : Object.values(response[key] ?? {}); const getDataFromAPI = async (response: AxiosResponse, key?: string): Promise => JSON.stringify( - response.headers['content-type'] === 'text/csv' ? await csv().fromString(response.data) : fromJson(response, key) + response.headers['content-type'] === 'text/csv' ? await csv().fromString(response.data) : fromJson(response.data, key) ); const fetchFrom = async ([source, key]: string[]): Promise => getDataFromAPI(await axios.get(source ?? ''), key); +const readFrom = async ([source, key]: string[]): Promise => + JSON.stringify(fromJson(JSON.parse(await fs.promises.readFile(source ?? '', 'utf-8')), key)); + export const transformerAction = async (transformerOptions: TransformerOptions): Promise => { await Promise.all([ transformerOptions.source.startsWith('http') ? await fetchFrom(transformerOptions.source.split('@')) - : fs.promises.readFile(transformerOptions.source, 'utf-8'), + : await readFrom(transformerOptions.source.split('@')), fs.promises.readFile(transformerOptions.configFile, 'utf-8') ]).then(([input, matching]: [string, string]): void => { const lieuxDeMediationNumerique: LieuMediationNumerique[] = JSON.parse(input) diff --git a/src/transformer/fields/date/date.field.spec.ts b/src/transformer/fields/date/date.field.spec.ts index 0c77c5ba..7209ab95 100644 --- a/src/transformer/fields/date/date.field.spec.ts +++ b/src/transformer/fields/date/date.field.spec.ts @@ -76,6 +76,17 @@ describe('date field', (): void => { expect(date).toEqual(new Date('2022-12-01T12:00:00.000Z')); }); + it('should process date field with value 1670421075', (): void => { + const date: Date = processDate( + { + datetime_latest: 1670421075 as unknown as string + }, + matching + ); + + expect(date).toEqual(new Date('2022-12-07T13:51:15.000Z')); + }); + it('should not process empty date', (): void => { expect((): void => { processDate( diff --git a/src/transformer/fields/date/date.field.ts b/src/transformer/fields/date/date.field.ts index 8ece5212..2b88fa25 100644 --- a/src/transformer/fields/date/date.field.ts +++ b/src/transformer/fields/date/date.field.ts @@ -5,6 +5,7 @@ type RegexResult = { month: string; day: string; time: string; + timestamp: string; }; export class DateCannotBeEmptyError extends Error { @@ -21,11 +22,14 @@ const FRENCH_DATE_REG_EXP: RegExp = /^(?\d{2})\/(?\d{1,2})\/(? const FRENCH_DATE_TIME_REG_EXP: RegExp = /^(?\d{2})\/(?\d{2})\/(?\d{4}) (?