Skip to content

Commit

Permalink
Pubblicato tool di aggiornamento
Browse files Browse the repository at this point in the history
  • Loading branch information
Samurai016 committed Jul 8, 2024
1 parent cf341a0 commit 6ec4d6c
Show file tree
Hide file tree
Showing 24 changed files with 1,249 additions and 8 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ docs/js
docs/css

# Ignore updater
updater
updater/node_modules
updater/package-lock.json
updater/.env
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,8 @@ Per ottenere i successivi 500 elementi è necessario specificare il parametro `p
**Essendo gli endpoint `/regioni` e `/province` molto leggeri, non è necessario specificare il parametro `page` per ottenere tutti i risultati.**

# Installazione su server proprio

Tramite questa repo è possibile installare l'API su una propria istanza di Supabase.
Tramite questa repo è possibile installare l'API su una propria istanza di Supabase seguendo la [guida di installazione]((https://github.com/Samurai016/Comuni-ITA/blob/master/setup)).

### Sistema di aggiornamento
Il sistema di aggiornamento della API prevede un sistema di logging tramite un bot Telegram. Il bot serve, oltre che per essere notificati sullo stato dell'aggiornamento da remoto, sia per la risoluzione di eventuali problemi/conflitti occorsi durante il fetch automatico dei dati.
Prima di poter installare l'API quindi, crea un bot Telegram tramite [BotFather](https://t.me/botfather) (Puoi chiamarlo come vuoi, il codice per il suo funzionamento è incluso in questa repo).
L'API è dotata di un sistema di aggiornamento semiautomatico che preleva i dati direttamente dagli archivi ISTAT e ministeriali e integra le informazioni mancanti interrogando Wikidata.
I dettagli sul funzionamento del sistema di aggiornamento sono disponibili [nell'apposita cartella](https://github.com/Samurai016/Comuni-ITA/blob/master/updater).
8 changes: 8 additions & 0 deletions updater/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
POSTGRES_HOST=
POSTGRES_PORT=
POSTGRES_DATABASE=
POSTGRES_USERNAME=
POSTGRES_PASSWORD=
TELEGRAM_BOT_KEY=
TELEGRAM_CHAT=
NODE_TLS_REJECT_UNAUTHORIZED=0
26 changes: 26 additions & 0 deletions updater/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module.exports = {
env: {
browser: true,
commonjs: true,
es2021: true
},
extends: 'standard',
overrides: [
{
env: {
node: true
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script'
}
}
],
parserOptions: {
ecmaVersion: 'latest'
},
rules: {
semi: ['error', 'always'],
indent: ['warning', 4]
}
};
7 changes: 7 additions & 0 deletions updater/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.vscode
/node_modules
package-lock.json
*.env

php/vendor
php/composer.lock
62 changes: 62 additions & 0 deletions updater/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Comuni ITA Updater

Questo tool permette di aggiornare i comuni italiani dell'API Comuni-ITA.
Il tool processa tutte le informazioni in automatico.
Potrebbe venir chiesto all'utente di inserire dei dati mancanti/errati.

Il tool è fruibile mediante:
* Interfaccia a riga di comando
* Bot Telegram

Il tool è in grado di esportare i dati:
* In formato JSON
* In formato SQL
* Aggiornando automaticamente il database Supabase (PostgreSQL)

## Installazione
* Installare [Node.js](https://nodejs.org/en/download/package-manager)
* Clonare il repository
* Eseguire `npm install` per installare le dipendenze
* Creare il file `.env` sulla base del file `.env.example`
* Eseguire il comando `npx comuni-ita-updater`

### File di configurazione `.env`
| Nome Variabile | Descrizione |
| --- | --- |
| `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_DATABASE`, `POSTGRES_USERNAME`, `POSTGRES_PASSWORD` | Configurazione del database PostgreSQL. Per quanto riguarda Supabase, è possibile trovare queste informazioni nella [sezione "Settings" del progetto](https://supabase.com/dashboard/project/_/settings/database). |
| `TELEGRAM_BOT_KEY` | Chiave del bot Telegram. Per creare un bot Telegram, seguire [questa guida](https://core.telegram.org/bots#how-do-i-create-a-bot). |
| `TELEGRAM_CHAT_ID` | ID della chat Telegram. Per ottenere l'ID della chat è posssibile utilizzare il bot [@myidbot](https://t.me/myidbot) |
| `NODE_TLS_REJECT_UNAUTHORIZED=0` | Disabilita la verifica dei certificati SSL. Questo è necessario per il fetch dei dati. |

## Utilizzo
Attraverso il comando
```
npx comuni-ita-updater --help
```
è possibile visualizzare l'elenco dei comandi disponibili.

Le opzioni disponibili sono:
| Opzione | Descrizione | Valori ammessi | Default |
| --- | --- | --- | --- |
| `--export` | Formato di esportazione dei dati.<br/><br/>In caso si impostasse `db`, il tool procederà a svuotare le tabelle `comuni`, `province` e `regioni` del database indicato nel file `.env` e inserirà automaticamente i nuovi dati aggiornati | `json`, `sql`, `db` | `json` |
| `--ui` | Interfaccia utente.<br/><br/>L'opzione `cli` avvia il tool in una console, le eventuali informazioni da inserire vengono richieste all'utente.<br/><br/>L'opzione `telegram` avvia il tool tramite il bot indicato da `TELEGRAM_BOT_KEY` e invierà i messaggi all'utente configurato dal parametro `TELEGRAM_CHAT_ID`. Le informazioni da inserire verranno ottenute dalle risposte ai messaggi (**Si intendono le risposte ai messaggi inviati dal bot. Un messaggio di testo che non sia una risposta non viene considerato dal bot**). | `cli`, `telegram` | `cli` |
| `--correzioni` | Path del file .json contenente le correzioni | | `correzioni.json` |

## Correzioni
Il file contenenente le correzioni deve avere la seguente struttura:
```json
{
"comuni": [
{
"codice": "A001", // Codice ISTAT del comune che si vuole correggere
... // Campi che vengono sovrascritti
}
],
"province": [
{
"codice": "01", // Codice ISTAT della provincia che si vuole correggere
... // Campi che vengono sovrascritti
}
],
}
```
19 changes: 19 additions & 0 deletions updater/correzioni.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"comuni": [
{
"codice": "012144",
"email": "[email protected]",
"pec": "[email protected]",
"telefono": "0332706691"
},
{
"codice": "063024",
"pec": "[email protected]"
},
{
"codice": "081025",
"email": "[email protected]",
"pec": "[email protected]"
}
]
}
8 changes: 8 additions & 0 deletions updater/correzioni.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Bardello con Malgesso e Bregano
UPDATE comuni SET email = '[email protected]', pec = '[email protected]', telefono = '0332706691' WHERE codice = '012144';

-- Castellammare di Stabia
UPDATE comuni SET pec = '[email protected]' WHERE codice = '063024';

-- Misiliscemi
UPDATE comuni SET email = '[email protected]', pec = '[email protected]' WHERE codice = '081025';
35 changes: 35 additions & 0 deletions updater/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "comuni-ita-updater",
"version": "1.0.0",
"description": "Updater for comuni-ita API",
"main": "src/index.js",
"type": "module",
"scripts": {
"start": "node --env-file=.env --no-deprecation --no-warnings src/index.js"
},
"bin": {
"comuni-ita-updater": "src/index.js"
},
"author": "Nicolò Rebaioli <[email protected]> (https://rebaioli.altervista.org/)",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"dotenv": "^16.4.5",
"inquirer": "^8.0.0",
"knex": "^3.1.0",
"node-fetch": "^3.3.2",
"node-html-parser": "^6.1.13",
"ora": "^8.0.1",
"pg": "^8.12.0",
"telegraf": "^4.16.3",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz",
"yargs": "^17.7.2"
},
"devDependencies": {
"eslint": "^8.44.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^16.0.1",
"eslint-plugin-promise": "^6.1.1"
}
}
19 changes: 16 additions & 3 deletions updater/src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#!/usr/bin/env node

import 'dotenv/config';
import steps from './steps.js';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';

// Suppress warnings
process.emitWarning = () => { return; };

(async () => {
const argv = yargs(hideBin(process.argv))
.usage('Usage: $0 [options]')
.usage('Usage: npx comuni-ita-updater [options]')
.option('u', {
alias: 'ui',
describe: `L'interfaccia utente da utilizzare`,
Expand All @@ -15,10 +21,16 @@ import { hideBin } from 'yargs/helpers';
.option('e', {
alias: 'export',
describe: `Modalità di esportazione`,
choices: ['sql', 'db'],
choices: ['sql', 'db', 'json'],
default: 'sql',
global: true
})
.option('c', {
alias: 'correzioni',
describe: `Percorso del file JSON contenente le correzioni`,
default: 'correzioni.json',
global: true
})
.argv;

// Get the UI requested by the user
Expand All @@ -27,5 +39,6 @@ import { hideBin } from 'yargs/helpers';

// Start the UI
const app = new UI.default(steps, argv);
app.run();
await app.run();
process.exit();
})();
19 changes: 19 additions & 0 deletions updater/src/steps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Step1 from "./steps/step1.js";
import Step2 from "./steps/step2.js";
import Step3 from "./steps/step3.js";
import Step4 from "./steps/step4.js";
import Step5 from "./steps/step5.js";
import Step6 from "./steps/step6.js";
import Step7 from "./steps/step7.js";
import Step8 from "./steps/step8.js";

export default [
Step1,
Step2,
Step3,
Step4,
Step5,
Step6,
Step7,
Step8
];
31 changes: 31 additions & 0 deletions updater/src/steps/step1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import fetch from 'node-fetch';
import * as xlsx from 'xlsx';
import https from 'https';
import crypto from 'crypto';

export default class Step1 {
constructor(state, ui, argv) {
this.state = state;
this.ui = ui;
this.argv = argv;
}

get name() {
return "Scaricando l'elenco dei comuni dal sito ISTAT";
}

async run() {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
const agent = new https.Agent({
rejectUnauthorized: false,
secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,
});
const response = await fetch("https://www.istat.it/storage/codici-unita-amministrative/Elenco-comuni-italiani.xls", { agent });
const buffer = await response.arrayBuffer();
const workbook = xlsx.read(buffer);
const csv = xlsx.utils.sheet_to_csv(workbook.Sheets[workbook.SheetNames[0]]).split("\n");

this.state.agent = agent;
this.state.csv = csv;
}
}
58 changes: 58 additions & 0 deletions updater/src/steps/step2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
sanitizeRegione,
sanitizeProvincia,
} from "../utils/utils.js";

export default class Step2 {
constructor(state, ui, argv) {
this.state = state;
this.ui = ui;
this.argv = argv;
}

get name() {
return "Estrazione dei dati ISTAT";
}

async run() {
const comuni = [];
const regioni = [];
const province = new Map();
const csv = this.state.csv;

for (let i = 3; i < csv.length; i++) {
const comune = csv[i].split(",");

if (comune[5]) {
const nome = comune[5]?.trim();
comuni.push({
nome: nome.indexOf("/") >= 0 ? nome.substring(0, nome.indexOf("/")) : nome,
nomeStraniero: nome.indexOf("/") >= 0 ? nome.substring(nome.indexOf("/") + 1) : null,
codice: comune[4]?.trim(),
codiceCatastale: comune[19]?.trim(),
regione: sanitizeRegione(comune[10]),
provincia: sanitizeProvincia(comune[11]),
});
}

// Province
if (comune[2] && !province.has(comune[2]?.trim())) {
province.set(comune[2]?.trim(), {
nome: sanitizeProvincia(comune[11]),
codice: comune[2]?.trim(),
sigla: comune[14]?.trim().toUpperCase(),
regione: sanitizeRegione(comune[10]),
});
}

// Regioni
if (comune[10] && !regioni.includes(sanitizeRegione(comune[10]))) {
regioni.push(sanitizeRegione(comune[10]));
}
}

this.state.comuni = comuni;
this.state.regioni = regioni;
this.state.province = province;
}
}
Loading

0 comments on commit 6ec4d6c

Please sign in to comment.