/* 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; });