api/importGasStations.js
2022-06-27 14:47:41 +02:00

236 lines
6.0 KiB
JavaScript

/* eslint-disable no-console */
/* eslint-disable global-require */
/* eslint-disable import/no-dynamic-require */
const fs = require("fs");
const parser = require("xml2json");
const htmlparser = require("node-html-parser").parse;
const moment = require("moment");
const Mongoose = require("mongoose");
const iconv = require("iconv-lite");
const request = require("request");
const config = require("./config");
// TODO: envoyer mail lors d'une erreur
Mongoose.set("useNewUrlParser", true);
Mongoose.set("useFindAndModify", false);
Mongoose.set("useCreateIndex", true);
Mongoose.set("debug", config.mongodbDebug);
Mongoose.connect(config.mongodbUrl, config.mondeDbOptions);
// Initialisation de la connexion à MongoDB
const db = () => {
const m = {};
fs.readdirSync("./models")
.filter(file => {
return (
file.indexOf(".") !== 0 &&
file.slice(-3) === ".js" &&
file !== "index.js"
);
})
.forEach(file => {
const model = require(`./models/${file.replace(".js", "")}`)(Mongoose);
m[model.modelName] = model;
});
return m;
};
const models = db();
let foundGasStations = 0; // Nombre total de station trouvée dans le fichier XML
let done = 0; // Nombre de stations mise à jour
/**
* Fonction permettant d'extraire et de convertir la liste des prix des carburants d'une station
* @param {Object} station
*/
const extractPrice = station => {
const prices = [];
if (station.prix) {
for (let i = 0; i < station.prix.length; i += 1) {
const currentPrice = station.prix[i];
prices.push({
gasType: currentPrice.nom,
price: currentPrice.valeur,
updatedAt: moment(currentPrice.maj)
});
}
}
return prices;
};
/**
* Fonction permettant de transformer une string en latitude ou longitude
* @param {String} value
*/
const convertValueToPosition = value => {
return Number(value) / 100000;
};
/**
* Fonction permettant de mettre à jour les prix d'une station
* @param {Object} station
* @param {Function} callback
*/
const createOrUpdateGasStation = (station, callback) => {
models.Stations.findOne({
stationId: station.stationId
})
.then(item => {
if (item) {
item
.update({
name: item.name || null,
stationId: station.stationId,
location: station.location,
prices: station.prices,
services: station.services,
postCode: station.postCode,
address: station.address,
city: station.city
})
.then(() => {
callback(null);
})
.catch(callback);
} else {
// Create item
const newItem = new models.Stations(station);
newItem
.save()
.then(() => {
callback(null);
})
.catch(callback);
}
})
.catch(callback);
};
/**
* Fonction permettant de retrouver le nom d'une station
* @param {Number} start
* @param {Function} callback
*/
const getStationName = (start, callback) => {
models.Stations.find({
name: null
})
.skip(start)
.limit(1)
.then(items => {
if (items && items.length === 1) {
const item = items[0];
const options = {
method: "POST",
url: `https://www.prix-carburants.gouv.fr/map/recupererInfosPdv/${item.stationId}`,
headers: {
"X-Requested-With": "XMLHttpRequest"
}
};
request(options, (err, response, body) => {
if (err) {
callback(err);
} else {
const html = htmlparser(body);
const name = html
.querySelector("strong");
if ( name ) {
name = name
.toString()
.replace(/[<>/]/g, "")
.replace(/strong/g, "") || null;
}
if (name) {
item.name = name;
item.save(errUpdate => {
if (errUpdate) {
callback(err);
} else {
getStationName(start + 1, callback);
}
});
}
}
});
} else {
callback(null);
}
})
.catch(callback);
};
/**
* Fonction permettant de stoper le script une fois celui-ci terminé
*/
const next = () => {
if (done === foundGasStations) {
console.log("All price updated!");
// Une fois tous les prix mis à jour on maj le nom de la station
getStationName(0, err => {
if (err) {
console.log("Done with error:", err);
} else {
console.log(`Done for ${done} stations`);
}
process.exit();
});
}
};
// INFO: le script commence réellement ici
fs.readFile("public/gas-stations.xml", function(err, data) {
if (err) {
console.log("ERR:", err);
process.exit();
return false;
}
const json = parser.toJson(iconv.decode(data, "ISO-8859-1"));
const rawStations = JSON.parse(json).pdv_liste.pdv;
const stations = [];
// Parcours de la liste des stations issues du XML pour en extraire les informations
for (let i = 0; i < rawStations.length; i += 1) {
const currentStation = rawStations[i];
stations.push({
stationId: currentStation.id,
location: {
type: "Point",
coordinates: [
convertValueToPosition(currentStation.longitude),
convertValueToPosition(currentStation.latitude)
]
},
prices: extractPrice(currentStation),
services:
currentStation.services && currentStation.services.service
? currentStation.services.service
: [],
postCode: currentStation.cp.toString(),
address: currentStation.adresse,
city: currentStation.ville
});
}
foundGasStations = stations.length;
// Pour chaque station correctement formatée on maj ses prix (ou on l'insère en base)
stations.forEach(type => {
createOrUpdateGasStation(type, () => {
done += 1;
next();
});
});
return true;
});