diff --git a/manifest.konnector b/manifest.konnector index fa1753fa9626a27fd6331b51ba88c12d27559431..57c9815ee76c4af9e1453d9d689dc0b5a884007f 100644 --- a/manifest.konnector +++ b/manifest.konnector @@ -1,5 +1,5 @@ { - "version": "1.0.4", + "version": "1.0.3", "name": "EGL", "type": "konnector", "language": "node", diff --git a/package.json b/package.json index 6fdbd73ad59650223527ff425e3563aaf66ed3c2..d2499de0b1c81b48f16eb4582f5d1c7dc1d49482 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egl", - "version": "1.0.4", + "version": "1.0.3", "description": "", "repository": { "type": "git", @@ -41,8 +41,7 @@ "dependencies": { "cozy-konnector-libs": "4.42.3", "moment": "^2.24.0", - "moment-timezone": "^0.5.26", - "node-fetch": "2" + "moment-timezone": "^0.5.26" }, "devDependencies": { "@types/moment-timezone": "^0.5.30", diff --git a/src/index.js b/src/index.js index 4fb9fbb3ba5d32a19e78f78099db016eb753777f..10131dbf3c2c2d7786488737eb917c37b306dab7 100644 --- a/src/index.js +++ b/src/index.js @@ -5,44 +5,45 @@ const { addData, hydrateAndFilter, cozyClient -} = require('cozy-konnector-libs') +} = require("cozy-konnector-libs"); -const fetch = require('node-fetch') -const moment = require('moment') -require('moment-timezone') +// const fetch = require('node-fetch') +const rp = require("request-promise"); +const moment = require("moment"); +require("moment-timezone"); -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 + process.env.COZY_JOB_MANUAL_EXECUTION === "true" ? true : false; const startDate = manualExecution ? moment() - .subtract(1, 'year') - .format('MM/DD/YYYY') + .subtract(1, "year") + .format("MM/DD/YYYY") : moment() - .subtract(3, 'year') - .format('MM/DD/YYYY') + .subtract(3, "year") + .format("MM/DD/YYYY"); -const endDate = moment().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, @@ -52,32 +53,32 @@ async function start(fields, cozyParameters) { // Local debug data // const baseUrl = fields.eglBaseURL // const apiAuthKey = fields.eglAPIAuthKey - 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') + ); + log("info", "Successfully logged in"); - const eglData = await getData(response, baseUrl, apiAuthKey) + const eglData = await getData(response, baseUrl, apiAuthKey); if (eglData) { - log('debug', 'Process egl daily data') + 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) + ); + log("debug", "Agregate egl load data for month and year"); + await agregateMonthAndYearData(processedLoadData); } else { - log('debug', 'No data found') + log("debug", "No data found"); } } catch (error) { - throw new Error(error.message) + throw new Error(error.message); } } @@ -89,15 +90,15 @@ async function start(fields, cozyParameters) { */ async function processData(data, doctype, filterKeys) { // const formatedData = await formateData(data) - log('debug', 'processData - data formated') + 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') + }); + log("debug", "processData - data filtered"); // Store new day data - await storeData(filteredData, doctype, filterKeys) - return filteredData + await storeData(filteredData, doctype, filterKeys); + return filteredData; } /** @@ -106,32 +107,32 @@ async function processData(data, doctype, filterKeys) { 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 = {} + 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 + "-" + 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) - }) + : (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' - ]) + "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']) + "com.grandlyon.egl.year" + ); + await storeData(agregatedYearData, "com.grandlyon.egl.year", ["year"]); } } @@ -140,130 +141,131 @@ async function agregateMonthAndYearData(data) { * Return an Array of agregated data */ async function buildAgregatedData(data, doctype) { - log('info', 'entering buildAgregatedData') - let agregatedData = [] + log("info", "entering buildAgregatedData"); + let agregatedData = []; for (let [key, value] of Object.entries(data)) { - const data = await buildDataFromKey(doctype, key, value) - const oldValue = await resetInProgressAggregatedData(data, doctype) - log('info', 'Dataload + oldvalue is ' + data.load + ' + ' + oldValue) - data.load += oldValue - agregatedData.push(data) + const data = await buildDataFromKey(doctype, key, value); + const oldValue = await resetInProgressAggregatedData(data, doctype); + log("info", "Dataload + oldvalue is " + data.load + " + " + oldValue); + data.load += oldValue; + agregatedData.push(data); } - return agregatedData + return agregatedData; } async function authenticate(login, password, baseUrl, apiAuthKey) { const authRequest = { method: "POST", + uri: baseUrl + "/connect.aspx", headers: { AuthKey: apiAuthKey, "Content-Type": "application/x-www-form-urlencoded" }, - body: new URLSearchParams({ + formData: { login: login, pass: password - }) - } - const data = await fetch(baseUrl + "/connect.aspx", authRequest) - const response = await data.json() - + }, + json: true + }; + 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", headers: { AuthKey: apiAuthKey, - 'Content-Type': 'application/x-www-form-urlencoded' + "Content-Type": "application/x-www-form-urlencoded" }, - body: new URLSearchParams({ + form: { token: response.resultatRetour.token, num_abt: response.resultatRetour.num_abt, date_debut: startDate, date_fin: endDate - }) - } + }, + json: true + }; try { // Sort data by date - const data = await fetch( - baseUrl + "/getAllAgregatsByAbonnement.aspx", - dataRequest - ) - const responseEgl = await data.json() - responseEgl.resultatRetour.sort(function(a, b) { - return new Date(a.DateReleve) - new Date(b.DateReleve); - }) + + const responseEgl = await rp(dataRequest).then(eglRawData => { + eglRawData.resultatRetour.sort(function(a, b) { + return new Date(a.DateReleve) - new Date(b.DateReleve); + }); + return eglRawData; + }); switch (responseEgl.codeRetour) { case 100: - return format(responseEgl) + return format(responseEgl); case -2: - throw errors.LOGIN_FAILED + throw errors.LOGIN_FAILED; case -1: - throw errors.VENDOR_DOWN + throw errors.VENDOR_DOWN; default: - throw errors.UNKNOWN_ERROR + throw errors.UNKNOWN_ERROR; } } catch (error) { - log('debug', 'Error from getAllAgregatsByAbonnement') - throw new Error(errors.VENDOR_DOWN) + log("debug", "Error from getAllAgregatsByAbonnement"); + 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); // Store first value as reference for index processing - let refValue = response.resultatRetour[0] + let refValue = response.resultatRetour[0]; // Create copy of data without first value const data = response.resultatRetour .slice(1) - .filter(value => value.ValeurIndex) - log('info', 'filtered size is : ' + data.length) + .filter(value => value.ValeurIndex); + log("info", "filtered size is : " + data.length); return data.map(value => { - const time = moment(value.DateReleve, moment.ISO_8601) - const procesedLoad = value.ValeurIndex - refValue.ValeurIndex + const time = moment(value.DateReleve, moment.ISO_8601); + const procesedLoad = value.ValeurIndex - refValue.ValeurIndex; if (procesedLoad < 0) { log( - 'error', - `processing load for day ${parseInt(time.format('D'))}/${parseInt( - time.format('M') - )}/${parseInt(time.format('YYYY'))}, value is : ${procesedLoad}` - ) - throw errors.VENDOR_DOWN + "error", + `processing load for day ${parseInt(time.format("D"))}/${parseInt( + time.format("M") + )}/${parseInt(time.format("YYYY"))}, value is : ${procesedLoad}` + ); + throw errors.VENDOR_DOWN; } // Change index ref value - refValue = value + refValue = value; return { load: procesedLoad, - 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 - } - }) + }; + }); } /** * 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); // }); const filteredDocuments = await hydrateAndFilter(data, doctype, { keys: filterKeys - }) - return await addData(filteredDocuments, doctype) + }); + return await addData(filteredDocuments, doctype); } /** @@ -273,24 +275,24 @@ async function storeData(data, doctype, filterKeys) { * 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 + 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] + const split = key.split("-"); + year = split[0]; + month = split[1]; + day = split[2]; + hour = split[3]; } return { load: Math.round(value * 10000) / 10000, @@ -299,7 +301,7 @@ async function buildDataFromKey(doctype, key, value) { day: parseInt(day), hour: parseInt(hour), minute: 0 - } + }; } /** @@ -311,21 +313,21 @@ async function buildDataFromKey(doctype, key, value) { */ 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) + 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 === 'com.grandlyon.egl.year') { + var filtered = []; + if (doctype === "com.grandlyon.egl.year") { // Yearly case filtered = result.filter(function(el) { - return el.year == data.year - }) - } else if (doctype === 'com.grandlyon.egl.month') { + 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 - }) + return el.year == data.year && el.month == data.month; + }); } else { // Hourly case filtered = result.filter(function(el) { @@ -334,17 +336,17 @@ async function resetInProgressAggregatedData(data, doctype) { el.month == data.month && el.day == data.day && el.hour == data.hour - ) - }) + ); + }); } // Remove data - let sum = 0.0 + let sum = 0.0; for (const doc of filtered) { - sum += doc.load - log('debug', 'Removing this entry for ' + doc.load) - 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 sum; } - return 0.0 + return 0.0; } diff --git a/yarn.lock b/yarn.lock index fe8b6b558ac239ed6bbfe9a88da8b05fd668027c..b3e2163bd8022d5c51ee728070eaa0a03162e72d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4406,13 +4406,6 @@ nock@^12.0.3: lodash "^4.17.13" propagate "^2.0.0" -node-fetch@2: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - node-fetch@2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" @@ -6323,11 +6316,6 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -6585,11 +6573,6 @@ watchpack@^2.2.0: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - webpack-cli@3.3.12: version "3.3.12" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a" @@ -6701,14 +6684,6 @@ webpack@5.38.1: watchpack "^2.2.0" webpack-sources "^2.3.0" -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"