222 lines
5.6 KiB
JavaScript
222 lines
5.6 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: parseInt(currentPrice.valeur, 10) / 1000,
|
|
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(station)
|
|
.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")
|
|
.toString()
|
|
.replace(/[<>/]/g, "")
|
|
.replace(/strong/g, "");
|
|
|
|
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;
|
|
});
|