From cba9031db83d3b9f778e41c4b0981b886cba3d00 Mon Sep 17 00:00:00 2001 From: git-directory-deploy <> Date: Thu, 25 Feb 2021 16:40:21 +0100 Subject: [PATCH] publish: update egl generated from commit 55779530e839cf138a02ceb037380da37dc2d9a1 --- index.js | 453 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 291 insertions(+), 162 deletions(-) diff --git a/index.js b/index.js index 506592c..aead142 100644 --- a/index.js +++ b/index.js @@ -95,39 +95,46 @@ const { addData, hydrateAndFilter, cozyClient -} = __webpack_require__(1); +} = __webpack_require__(1) -const rp = __webpack_require__(24); -const moment = __webpack_require__(1492); -__webpack_require__(1630); +const rp = __webpack_require__(24) +const moment = __webpack_require__(1492) +__webpack_require__(1630) -moment.locale("fr"); // set the language -moment.tz.setDefault("Europe/Paris"); // set the timezone +moment.locale('fr') // set the language +moment.tz.setDefault('Europe/Paris') // set the timezone -const manualExecution = process.env.COZY_JOB_MANUAL_EXECUTION === "true" ? true : false +const manualExecution = + process.env.COZY_JOB_MANUAL_EXECUTION === 'true' ? true : false const startDate = manualExecution - ? moment().startOf("year").subtract(1, "year").format("MM/DD/YYYY") - : moment().startOf("year").subtract(3, "year").format("MM/DD/YYYY") - -const endDate = moment().format("MM/DD/YYYY"); -const timeRange = ["day", "month", "year"]; + ? moment() + .startOf('year') + .subtract(1, 'year') + .format('MM/DD/YYYY') + : moment() + .startOf('year') + .subtract(3, 'year') + .format('MM/DD/YYYY') + +const endDate = moment().format('MM/DD/YYYY') +// const timeRange = ['day', 'month', 'year'] const rangeDate = { day: { - doctype: "com.grandlyon.egl.day", - keys: ["year", "month", "day"] + doctype: 'com.grandlyon.egl.day', + keys: ['year', 'month', 'day'] }, month: { - doctype: "com.grandlyon.egl.month", - keys: ["year", "month"] + doctype: 'com.grandlyon.egl.month', + keys: ['year', 'month'] }, year: { - doctype: "com.grandlyon.egl.year", - keys: ["year"] + doctype: 'com.grandlyon.egl.year', + keys: ['year'] } -}; +} -module.exports = new BaseKonnector(start); +module.exports = new BaseKonnector(start) // The start function is run by the BaseKonnector instance only when it got all the account // information (fields). When you run this connector yourself in "standalone" mode or "dev" mode, @@ -136,80 +143,159 @@ async function start(fields, cozyParameters) { try { // resetting data for demo only // await resetData() - const baseUrl = cozyParameters.secret.eglBaseURL; - const apiAuthKey = cozyParameters.secret.eglAPIAuthKey; - log("info", "Authenticating ..."); + const baseUrl = cozyParameters.secret.eglBaseURL + const apiAuthKey = cozyParameters.secret.eglAPIAuthKey + log('info', 'Authenticating ...') const response = await authenticate( fields.login, fields.password, baseUrl, apiAuthKey - ); - log("info", "Successfully logged in"); - Promise.all( - timeRange.map(timeStep => - processData(timeStep, response, baseUrl, apiAuthKey) + ) + log('info', 'Successfully logged in') + + const eglData = await getData(response, baseUrl, apiAuthKey) + if (eglData) { + log('debug', 'Process egl daily data') + const processedLoadData = await processData( + eglData, + rangeDate.day.doctype, + rangeDate.day.keys ) - ); + log('debug', 'Agregate egl load data for month and year') + await agregateMonthAndYearData(processedLoadData) + } else { + log('debug', 'No data found') + } } catch (error) { - throw new Error(error.message); - } -} -async function processData(timeStep, response, baseUrl, apiAuthKey) { - const doctype = rangeDate[timeStep].doctype; - const loadProfile = await getData(response, baseUrl, apiAuthKey); - log("info", "Saving data to Cozy"); - if (doctype === rangeDate.day.doctype) { - await storeData(loadProfile, rangeDate.day.doctype, rangeDate.day.keys); - } else if (doctype === rangeDate.month.doctype) { - await resetInProgressAggregatedData(rangeDate.month.doctype); - const monthlyData = processMonthlyAggregation(loadProfile, rangeDate.month); - log("info", "Saving monthly data"); - await storeData(monthlyData, rangeDate.month.doctype, rangeDate.month.keys); - } else if (doctype === rangeDate.year.doctype) { - await resetInProgressAggregatedData(rangeDate.year.doctype); - const yearlyData = processYearAggregation( - loadProfile, - rangeDate.year.doctype - ); - log("info", "Saving yearly data"); - await storeData(yearlyData, rangeDate.year.doctype, rangeDate.year.keys); - } else { - throw new Error("Unkonw range type: " + doctype); + throw new Error(error.message) } } +/** + * Parse data + * Remove existing data from DB using hydrateAndFilter + * Store filtered data + * Return the list of filtered data + */ +async function processData(data, doctype, filterKeys) { + // const formatedData = await formateData(data) + log('debug', 'processData - data formated') + // Remove data for existing days into the DB + const filteredData = await hydrateAndFilter(data, doctype, { + keys: filterKeys + }) + log('debug', 'processData - data filtered') + // Store new day data + await storeData(filteredData, doctype, filterKeys) + return filteredData +} + +/** + * Agregate data from daily data to monthly and yearly data + */ +async function agregateMonthAndYearData(data) { + // Sum year and month values into object with year or year-month as keys + if (data && data.length !== 0) { + let monthData = {} + let yearData = {} + + data.forEach(element => { + element.year + '-' + element.month in monthData + ? (monthData[element.year + '-' + element.month] += element.load) + : (monthData[element.year + '-' + element.month] = element.load) + element.year in yearData + ? (yearData[element.year] += element.load) + : (yearData[element.year] = element.load) + }) + // Agregation for Month data + const agregatedMonthData = await buildAgregatedData( + monthData, + 'com.grandlyon.egl.month' + ) + await storeData(agregatedMonthData, 'com.grandlyon.egl.month', [ + 'year', + 'month' + ]) + // Agregation for Year data + const agregatedYearData = await buildAgregatedData( + yearData, + 'com.grandlyon.egl.year' + ) + await storeData(agregatedYearData, 'com.grandlyon.egl.year', ['year']) + } +} + +/** + * Retrieve and remove old data for a specific doctype + * Return an Array of agregated data + */ +async function buildAgregatedData(data, doctype) { + let agregatedData = [] + for (let [key, value] of Object.entries(data)) { + const data = await buildDataFromKey(doctype, key, value) + const oldValue = await resetInProgressAggregatedData(data, doctype) + data.load += oldValue + agregatedData.push(data) + } + return agregatedData +} + +// async function processData(timeStep, response, baseUrl, apiAuthKey) { +// const doctype = rangeDate[timeStep].doctype; +// const loadProfile = await getData(response, baseUrl, apiAuthKey); +// log("info", "Saving data to Cozy"); +// if (doctype === rangeDate.day.doctype) { +// await storeData(loadProfile, rangeDate.day.doctype, rangeDate.day.keys); +// } else if (doctype === rangeDate.month.doctype) { +// await resetInProgressAggregatedData(rangeDate.month.doctype); +// const monthlyData = processMonthlyAggregation(loadProfile, rangeDate.month); +// log("info", "Saving monthly data"); +// await storeData(monthlyData, rangeDate.month.doctype, rangeDate.month.keys); +// } else if (doctype === rangeDate.year.doctype) { +// await resetInProgressAggregatedData(rangeDate.year.doctype); +// const yearlyData = processYearAggregation( +// loadProfile, +// rangeDate.year.doctype +// ); +// log("info", "Saving yearly data"); +// await storeData(yearlyData, rangeDate.year.doctype, rangeDate.year.keys); +// } else { +// throw new Error("Unkonw range type: " + doctype); +// } +// } + async function authenticate(login, password, baseUrl, apiAuthKey) { const authRequest = { - method: "POST", - uri: baseUrl + "/connect.aspx", + method: 'POST', + uri: baseUrl + '/connect.aspx', headers: { AuthKey: apiAuthKey, - "Content-Type": "application/x-www-form-urlencoded" + 'Content-Type': 'application/x-www-form-urlencoded' }, form: { login: login, pass: password }, json: true - }; - const response = await rp(authRequest); + } + const response = await rp(authRequest) if (response.codeRetour === 100) { - return response; + return response } else { - throw new Error(errors.LOGIN_FAILED); + throw new Error(errors.LOGIN_FAILED) } } async function getData(response, baseUrl, apiAuthKey) { - log("debug", "Start date : " + startDate); - log("debug", "End date : " + endDate); + log('debug', 'Start date : ' + startDate) + log('debug', 'End date : ' + endDate) const dataRequest = { - method: "POST", - uri: baseUrl + "/getAllAgregatsByAbonnement.aspx", + method: 'POST', + uri: baseUrl + '/getAllAgregatsByAbonnement.aspx', headers: { AuthKey: apiAuthKey, - "Content-Type": "application/x-www-form-urlencoded" + 'Content-Type': 'application/x-www-form-urlencoded' }, form: { token: response.resultatRetour.token, @@ -218,116 +304,116 @@ async function getData(response, baseUrl, apiAuthKey) { date_fin: endDate }, json: true - }; + } try { - const responseEgl = await rp(dataRequest); + const responseEgl = await rp(dataRequest) switch (responseEgl.codeRetour) { case 100: - return format(responseEgl); + return format(responseEgl) case -2: - throw new Error(errors.LOGIN_FAILED); + throw new Error(errors.LOGIN_FAILED) case -1: - throw new Error(errors.VENDOR_DOWN); + throw new Error(errors.VENDOR_DOWN) default: - throw new Error(errors.UNKNOWN_ERROR); + throw new Error(errors.UNKNOWN_ERROR) } } catch (error) { - throw new Error(errors.VENDOR_DOWN); + throw new Error(errors.VENDOR_DOWN) } } function format(response) { - log("info", "origin response size is : " + response.resultatRetour.length) + log('info', 'origin response size is : ' + response.resultatRetour.length) const data = response.resultatRetour .slice(1) - .filter(value => value.ValeurIndex); - const dataLen = data.length; - log("info", "filtered size is : " + dataLen); + .filter(value => value.ValeurIndex) + const dataLen = data.length + log('info', 'filtered size is : ' + dataLen) const mapData = data.map((value, index) => { - const time = moment(value.DateReleve, moment.ISO_8601); + const time = moment(value.DateReleve, moment.ISO_8601) if (index + 1 < dataLen) { return { load: data[index + 1].ValeurIndex - value.ValeurIndex, - year: parseInt(time.format("YYYY")), - month: parseInt(time.format("M")), - day: parseInt(time.format("D")), + year: parseInt(time.format('YYYY')), + month: parseInt(time.format('M')), + day: parseInt(time.format('D')), hour: 0, minute: 0, type: value.TypeAgregat - }; + } } else { - log("info", "end of data - date is : " + value.DateReleve); + log('info', 'end of data - date is : ' + value.DateReleve) return { load: null, - year: parseInt(time.format("YYYY")), - month: parseInt(time.format("M")), - day: parseInt(time.format("D")), + year: parseInt(time.format('YYYY')), + month: parseInt(time.format('M')), + day: parseInt(time.format('D')), hour: 0, minute: 0, type: value.TypeAgregat - }; + } } - }); - return mapData; -} - -function processYearAggregation(data, doctype) { - log("info", "Start aggregation for : " + doctype); - const grouped = data.reduce(reduceYearFunction, {}); - return Object.values(grouped); -} - -function processMonthlyAggregation(data, range) { - log("info", "Start aggregation for : " + range.doctype); - // Filter by year - const tmpData = groupBy(data, "year"); - const keys = Object.keys(tmpData); - var dataToStore = []; - // Monthly aggregation - for (const index in keys) { - // Get daily data of a year - var monthlyData = tmpData[keys[index]]; - // Monthly aggregation - var aggregatedData = monthlyData.reduce(reduceMonthFunction, {}); - // Store it - dataToStore = dataToStore.concat(Object.values(aggregatedData)); - } - return dataToStore; -} - -function groupBy(xs, key) { - return xs.reduce(function(rv, x) { - (rv[x[key]] = rv[x[key]] || []).push(x); - return rv; - }, {}); -} - -function reduceYearFunction(acc, x) { - var id = acc[x.year]; - if (id) { - id.load += x.load; - } else { - acc[x.year] = x; - } - return acc; -} - -function reduceMonthFunction(acc, x) { - var id = acc[x.month]; - if (id) { - id.load += x.load; - } else { - acc[x.month] = x; - } - return acc; -} + }) + return mapData +} + +// function processYearAggregation(data, doctype) { +// log("info", "Start aggregation for : " + doctype); +// const grouped = data.reduce(reduceYearFunction, {}); +// return Object.values(grouped); +// } + +// function processMonthlyAggregation(data, range) { +// log("info", "Start aggregation for : " + range.doctype); +// // Filter by year +// const tmpData = groupBy(data, "year"); +// const keys = Object.keys(tmpData); +// var dataToStore = []; +// // Monthly aggregation +// for (const index in keys) { +// // Get daily data of a year +// var monthlyData = tmpData[keys[index]]; +// // Monthly aggregation +// var aggregatedData = monthlyData.reduce(reduceMonthFunction, {}); +// // Store it +// dataToStore = dataToStore.concat(Object.values(aggregatedData)); +// } +// return dataToStore; +// } + +// function groupBy(xs, key) { +// return xs.reduce(function(rv, x) { +// (rv[x[key]] = rv[x[key]] || []).push(x); +// return rv; +// }, {}); +// } + +// function reduceYearFunction(acc, x) { +// var id = acc[x.year]; +// if (id) { +// id.load += x.load; +// } else { +// acc[x.year] = x; +// } +// return acc; +// } + +// function reduceMonthFunction(acc, x) { +// var id = acc[x.month]; +// if (id) { +// id.load += x.load; +// } else { +// acc[x.month] = x; +// } +// return acc; +// } /** * Save data in the right doctype db and prevent duplicated keys */ async function storeData(data, doctype, filterKeys) { - log("debug", "Store into " + doctype); - log("debug", "Store into keys : " + filterKeys); + log('debug', 'Store into ' + doctype) + log('debug', 'Store into keys : ' + filterKeys) // data.map(v => { // log("info", "Saving data " + v.load + " for " + v.day + "/" + v.month + "/" + v.year); // }); @@ -337,44 +423,87 @@ async function storeData(data, doctype, filterKeys) { return await addData(filteredDocuments, doctype) } +/** + * Format an entry for DB storage + * using key and value + * For year doctype: key = "YYYY" + * For month doctype: key = "YYYY-MM" + */ +async function buildDataFromKey(doctype, key, value) { + let year, month, day, hour + if (doctype === 'com.grandlyon.egl.year') { + year = key + month = 1 + day = 0 + hour = 0 + } else if (doctype === 'com.grandlyon.egl.month') { + const split = key.split('-') + year = split[0] + month = split[1] + day = 0 + hour = 0 + } else { + const split = key.split('-') + year = split[0] + month = split[1] + day = split[2] + hour = split[3] + } + return { + load: Math.round(value * 10000) / 10000, + year: parseInt(year), + month: parseInt(month), + day: parseInt(day), + hour: parseInt(hour), + minute: 0 + } +} + /** * Function handling special case. * The temporary aggregated data need to be remove in order for the most recent one te be saved. * ex for com.grandlyon.egl.month : * { load: 76.712, month: 2020, ... } need to be replace by - * { load: 82.212, month: 2020, ... } after grdf data reprocess + * { load: 82.212, month: 2020, ... } after egl data reprocess */ -async function resetInProgressAggregatedData(doctype) { +async function resetInProgressAggregatedData(data, doctype) { // /!\ Warning: cannot use mongo queries because not supported for dev by cozy-konnectors-libs - log("debug", "Remove aggregated data for " + doctype); - const result = await cozyClient.data.findAll(doctype); - if (result.error || result.length <= 0) { - // eslint-disable-next-line no-console - console.warn("Error while fetching loads, doctype not found "); - } else { - const currentDate = moment(); + log('debug', 'Remove aggregated data for ' + doctype) + const result = await cozyClient.data.findAll(doctype) + if (result && result.length > 0) { // Filter data to remove - var filtered = []; - if (doctype === rangeDate.year.doctype) { + var filtered = [] + if (doctype === 'com.grandlyon.egl.year') { // Yearly case filtered = result.filter(function(el) { - return el.year == currentDate.year(); - }); - } else { + return el.year == data.year + }) + } else if (doctype === 'com.grandlyon.egl.month') { // Monthly case + filtered = result.filter(function(el) { + return el.year == data.year && el.month == data.month + }) + } else { + // Hourly case filtered = result.filter(function(el) { return ( - el.year == currentDate.year() && - el.month == parseInt(moment().format("M")) - ); - }); + el.year == data.year && + el.month == data.month && + el.day == data.day && + el.hour == data.hour + ) + }) } // Remove data + let sum = 0.0 for (const doc of filtered) { - log("debug", "Removing this entry for " + doc); - await cozyClient.data.delete(doctype, doc); + sum += doc.load + log('debug', 'Removing this entry for ' + doc.load) + await cozyClient.data.delete(doctype, doc) } + return sum } + return 0.0 } -- GitLab