From fc34c1db0b4def834c460afbbc81ae775c6b81e2 Mon Sep 17 00:00:00 2001 From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com> Date: Wed, 10 Aug 2022 16:40:12 +0200 Subject: [PATCH] publish: feat: implement on delateAccount generated from commit cb7c4bb29acfc9e4f6fdc13eb8c7181d1f1034ff --- index.js | 676 +++++++++++++++++++++++++-------------------- manifest.konnector | 3 +- package.json | 2 + 3 files changed, 374 insertions(+), 307 deletions(-) diff --git a/index.js b/index.js index b34ad24..8bb9405 100644 --- a/index.js +++ b/index.js @@ -32,7 +32,7 @@ const { getBoConsent, deleteBoConsent, } = __webpack_require__(1557) -const { verifyUserIdentity } = __webpack_require__(1558) +const { verifyUserIdentity } = __webpack_require__(1595) const { activateContract } = __webpack_require__(1598) const { verifyContract } = __webpack_require__(1599) const { terminateContract } = __webpack_require__(1601) @@ -160,9 +160,12 @@ async function start(fields, cozyParameters) { const userConsent = await getBoConsent(accountData.data.consentId) const user = await verifyUserIdentity(fields, baseUrl, apiAuthKey, sgeLogin) - if (user.lastname !== userConsent.lastname || !user) { + if ( + user.lastname.toLocaleUpperCase() !== + userConsent.lastname.toLocaleUpperCase() || + !user + ) { log('error', `Invalid or not found consent for user`) - await deleteBoConsent() if (userConsent.serviceId) { await terminateContract( baseUrl, @@ -172,6 +175,7 @@ async function start(fields, cozyParameters) { fields.pointId, userConsent.serviceId ) + await deleteBoConsent() } else { log('error', `No service id retrieved from BO`) throw errors.VENDOR_DOWN @@ -384,17 +388,26 @@ function processData(doctype = 'com.grandlyon.enedis.day') { throw err } // Return only needed part of info - const data = parseSgeXmlData(result) - const processedDailyData = await storeData( - await formateDataForDoctype(data), - doctype, - ['year', 'month', 'day', 'hour', 'minute'] - ) + log('info', doctype) + try { + const data = parseSgeXmlData(result) + const processedDailyData = await storeData( + await formateDataForDoctype(data), + doctype, + ['year', 'month', 'day', 'hour', 'minute'] + ) - log('info', 'Agregate enedis daily data for month and year') - if (doctype === 'com.grandlyon.enedis.day') { - log('info', 'Agregating...') - await agregateMonthAndYearData(processedDailyData) + log('info', 'Agregate enedis daily data for month and year') + if (doctype === 'com.grandlyon.enedis.day') { + log('info', 'Agregating...') + await agregateMonthAndYearData(processedDailyData) + } + } catch (e) { + if (doctype === 'com.grandlyon.enedis.minute') { + log('warn', `No half-hour activated`) + } else { + log('error', `Unkown error ${e}`) + } } } } @@ -148127,7 +148140,7 @@ const fs = __webpack_require__(149); const path = __webpack_require__(142); -let manifest = typeof {"version":"1.0.1","name":"Enedis SGE","type":"konnector","language":"node","icon":"icon.png","slug":"enedis-sge-grandlyon","source":"https://forge.grandlyon.com/web-et-numerique/llle_project/enedis-sge-konnector.git","editor":"Cozy","vendor_link":"Link to the target website","categories":["energy"],"frequency":"daily","fields":{"firstname":{"type":"string"},"lastname":{"type":"string"},"address":{"type":"string"},"postalCode":{"type":"string"},"city":{"type":"string"},"pointId":{"type":"number"}},"data_types":[],"screenshots":[],"permissions":{"accounts":{"type":"io.cozy.accounts"},"files":{"type":"io.cozy.files"},"enedis data":{"type":"com.grandlyon.enedis.*"}},"developer":{"name":"Métropole de Lyon","url":"https://www.grandlyon.com/"},"langs":["fr"],"locales":{"fr":{"short_description":"Récupère vos donnéees de courbe de charge depuis l'API Enedis","long_description":"Ce connecteur récupère la courbe de charge électrique enregistrée par le compteur Linky","permissions":{"enedis data":{"description":"Requises pour accéder et stocker les données collectées par le compteur Linky et exposées par les API Enedis (consommations d’électricité à la demi-heure, au jour, mois et année). "},"files":{"description":"Cozy files"},"accounts":{"description":"Utilisé pour accéder à vos données de consommation."}}},"en":{"short_description":"Fetches your electricity consumption data from Enedis API","long_description":"This konnector fetches the energy curve of your electricity consumption gathered by your Linky device.","permissions":{"enedis data":{"description":"Required to access and store the data collected by the Linky meter and exposed by Enedis APIs (half-an-hour, daily, monthly and yearly consumption)."},"files":{"description":"Cozy files"},"accounts":{"description":"Used to access your consumption data."}}}},"manifest_version":"2"} === 'undefined' ? {} : {"version":"1.0.1","name":"Enedis SGE","type":"konnector","language":"node","icon":"icon.png","slug":"enedis-sge-grandlyon","source":"https://forge.grandlyon.com/web-et-numerique/llle_project/enedis-sge-konnector.git","editor":"Cozy","vendor_link":"Link to the target website","categories":["energy"],"frequency":"daily","fields":{"firstname":{"type":"string"},"lastname":{"type":"string"},"address":{"type":"string"},"postalCode":{"type":"string"},"city":{"type":"string"},"pointId":{"type":"number"}},"data_types":[],"screenshots":[],"permissions":{"accounts":{"type":"io.cozy.accounts"},"files":{"type":"io.cozy.files"},"enedis data":{"type":"com.grandlyon.enedis.*"}},"developer":{"name":"Métropole de Lyon","url":"https://www.grandlyon.com/"},"langs":["fr"],"locales":{"fr":{"short_description":"Récupère vos donnéees de courbe de charge depuis l'API Enedis","long_description":"Ce connecteur récupère la courbe de charge électrique enregistrée par le compteur Linky","permissions":{"enedis data":{"description":"Requises pour accéder et stocker les données collectées par le compteur Linky et exposées par les API Enedis (consommations d’électricité à la demi-heure, au jour, mois et année). "},"files":{"description":"Cozy files"},"accounts":{"description":"Utilisé pour accéder à vos données de consommation."}}},"en":{"short_description":"Fetches your electricity consumption data from Enedis API","long_description":"This konnector fetches the energy curve of your electricity consumption gathered by your Linky device.","permissions":{"enedis data":{"description":"Required to access and store the data collected by the Linky meter and exposed by Enedis APIs (half-an-hour, daily, monthly and yearly consumption)."},"files":{"description":"Cozy files"},"accounts":{"description":"Used to access your consumption data."}}}},"manifest_version":"2"}; +let manifest = typeof {"version":"1.0.1","name":"Enedis SGE","type":"konnector","language":"node","icon":"icon.png","slug":"enedis-sge-grandlyon","source":"https://forge.grandlyon.com/web-et-numerique/llle_project/enedis-sge-konnector.git","editor":"Cozy","vendor_link":"Link to the target website","categories":["energy"],"frequency":"daily","fields":{"firstname":{"type":"string"},"lastname":{"type":"string"},"address":{"type":"string"},"postalCode":{"type":"string"},"city":{"type":"string"},"pointId":{"type":"number"}},"data_types":[],"screenshots":[],"permissions":{"accounts":{"type":"io.cozy.accounts"},"files":{"type":"io.cozy.files"},"enedis data":{"type":"com.grandlyon.enedis.*"}},"developer":{"name":"Métropole de Lyon","url":"https://www.grandlyon.com/"},"langs":["fr"],"locales":{"fr":{"short_description":"Récupère vos donnéees de courbe de charge depuis l'API Enedis","long_description":"Ce connecteur récupère la courbe de charge électrique enregistrée par le compteur Linky","permissions":{"enedis data":{"description":"Requises pour accéder et stocker les données collectées par le compteur Linky et exposées par les API Enedis (consommations d’électricité à la demi-heure, au jour, mois et année). "},"files":{"description":"Cozy files"},"accounts":{"description":"Utilisé pour accéder à vos données de consommation."}}},"en":{"short_description":"Fetches your electricity consumption data from Enedis API","long_description":"This konnector fetches the energy curve of your electricity consumption gathered by your Linky device.","permissions":{"enedis data":{"description":"Required to access and store the data collected by the Linky meter and exposed by Enedis APIs (half-an-hour, daily, monthly and yearly consumption)."},"files":{"description":"Cozy files"},"accounts":{"description":"Used to access your consumption data."}}}},"manifest_version":"2","on_delete_account":"onDeleteAccount.js"} === 'undefined' ? {} : {"version":"1.0.1","name":"Enedis SGE","type":"konnector","language":"node","icon":"icon.png","slug":"enedis-sge-grandlyon","source":"https://forge.grandlyon.com/web-et-numerique/llle_project/enedis-sge-konnector.git","editor":"Cozy","vendor_link":"Link to the target website","categories":["energy"],"frequency":"daily","fields":{"firstname":{"type":"string"},"lastname":{"type":"string"},"address":{"type":"string"},"postalCode":{"type":"string"},"city":{"type":"string"},"pointId":{"type":"number"}},"data_types":[],"screenshots":[],"permissions":{"accounts":{"type":"io.cozy.accounts"},"files":{"type":"io.cozy.files"},"enedis data":{"type":"com.grandlyon.enedis.*"}},"developer":{"name":"Métropole de Lyon","url":"https://www.grandlyon.com/"},"langs":["fr"],"locales":{"fr":{"short_description":"Récupère vos donnéees de courbe de charge depuis l'API Enedis","long_description":"Ce connecteur récupère la courbe de charge électrique enregistrée par le compteur Linky","permissions":{"enedis data":{"description":"Requises pour accéder et stocker les données collectées par le compteur Linky et exposées par les API Enedis (consommations d’électricité à la demi-heure, au jour, mois et année). "},"files":{"description":"Cozy files"},"accounts":{"description":"Utilisé pour accéder à vos données de consommation."}}},"en":{"short_description":"Fetches your electricity consumption data from Enedis API","long_description":"This konnector fetches the energy curve of your electricity consumption gathered by your Linky device.","permissions":{"enedis data":{"description":"Required to access and store the data collected by the Linky meter and exposed by Enedis APIs (half-an-hour, daily, monthly and yearly consumption)."},"files":{"description":"Cozy files"},"accounts":{"description":"Used to access your consumption data."}}}},"manifest_version":"2","on_delete_account":"onDeleteAccount.js"}; if (process.env.NODE_ENV !== undefined && process.env.NODE_ENV !== 'none' && process.env.NODE_ENV !== 'production') { try { @@ -223435,7 +223448,7 @@ function parseContractStartDate(result) { /** * Return User contract start date * @param {string} result - * @returns {Contract[]} + * @returns {Contract[] | Contract} */ function parseContracts(result) { log('info', 'Parsing contract') @@ -223833,6 +223846,7 @@ module.exports = { // @ts-check const { log } = __webpack_require__(1) +const { default: axios } = __webpack_require__(1558) /** * @param {number} pointId @@ -223882,27 +223896,29 @@ function updateBoConsent(consent, serviceId) { * @param {number} boId * @returns {Consent} */ -function getBoConsent(boId) { +async function getBoConsent(boId) { //TODO: Implement log('info', `Query getBoConsent ${boId}`) + // fields. + // const response = await axios.get(`${API_URL}/${postalCode}`) return { - pointId: 1234, - lastname: 'SUBTIL', + pointId: 19160781274487, + lastname: 'pouet', firstname: 'hugo', address: 'mad', postalCode: '69007', inseeCode: '69383', - serviceId: 1234, + serviceId: 71428567, } // throw errors.VENDOR_DOWN } /** * */ -function deleteBoConsent() { +function deleteBoConsent(boId) { //TODO: deleteBoConsent - log('info', `Query deleteBoConsent`) - throw new Error('Function not implemented.') + log('info', `Query deleteBoConsent ${boId}`) + // throw new Error('Function not implemented.') } module.exports = { @@ -223917,181 +223933,20 @@ module.exports = { /* 1558 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { -// @ts-check -const { log, errors } = __webpack_require__(1) -const { findUserPdl } = __webpack_require__(1559) -const { getInseeCode } = __webpack_require__(1560) - -/** - * Verify user identity - * @param {object} fields - * @param {string} baseUrl - * @param {string} apiAuthKey - * @param {string} loginUtilisateur - * @returns {Promise<User>} - */ -async function verifyUserIdentity( - fields, - baseUrl, - apiAuthKey, - loginUtilisateur -) { - const inseeCode = await getInseeCode(fields.postalCode) - - const pdl = await findUserPdl( - `${baseUrl}/enedis_SDE_recherche-point/1.0`, - apiAuthKey, - loginUtilisateur, - fields.lastname, - fields.address, - fields.postalCode, - inseeCode - ) - - if (fields.pointId != pdl) { - log('error', 'PointId does not match') - throw errors.LOGIN_FAILED - } - - return { - lastname: fields.lastname, - firstname: fields.firstname, - pointId: fields.pointId, - inseeCode, - postalCode: fields.postalCode, - address: fields.address, - } -} - -module.exports = { verifyUserIdentity } - +module.exports = __webpack_require__(1559); /***/ }), /* 1559 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { -// @ts-check -const { log, errors } = __webpack_require__(1) -const soapRequest = __webpack_require__(1331) -const { parseUserPdl, parseTags, parseValue } = __webpack_require__(1555) -const { rechercherPoint } = __webpack_require__(1556) -const xml2js = __webpack_require__(1513) - -/** - * @param {string} url - * @param {string} apiAuthKey - * @param {string} appLogin - * @param {string} name - * @param {string} address - * @param {string} postalCode - * @param {string} inseeCode - * @return {Promise<string | null>} User Pdl - */ -async function findUserPdl( - url, - apiAuthKey, - appLogin, - name, - address, - postalCode, - inseeCode -) { - log('info', 'Fetching user data') - const sgeHeaders = { - 'Content-Type': 'text/xml;charset=UTF-8', - apikey: apiAuthKey, - } - - const { response } = await soapRequest({ - url: url, - headers: sgeHeaders, - xml: rechercherPoint(appLogin, name, postalCode, inseeCode, address), - }).catch(err => { - log('error', 'rechercherPointResponse') - log('error', err) - throw errors.LOGIN_FAILED - }) - - const parsedReply = await xml2js.parseStringPromise(response.body, { - tagNameProcessors: [parseTags], - valueProcessors: [parseValue], - explicitArray: false, - }) - - try { - return parseUserPdl(parsedReply) - } catch (error) { - log('error', 'Error while parsing user PDL: ' + error) - throw errors.LOGIN_FAILED - } -} - -module.exports = { findUserPdl } - - -/***/ }), -/* 1560 */ -/***/ ((module, __unused_webpack_exports, __webpack_require__) => { - -// @ts-check -const { default: axios } = __webpack_require__(1561) -const { log, errors } = __webpack_require__(1) - -const API_URL = 'https://apicarto.ign.fr/api/codes-postaux/communes' - -/** - * Return inseeCode given a postalCode - * @param {string} postalCode - * @param {string} [city] - * @return {Promise<string>} inseeCode - */ -async function getInseeCode(postalCode, city) { - try { - log('info', `Query getInseeCode for postalCode ${postalCode} / ${city}`) - const response = await axios.get(`${API_URL}/${postalCode}`) - - if (response.data.length === 1) { - return response.data[0].codeCommune - } else { - if (!city) throw errors.USER_ACTION_NEEDED - - const filteredResponse = response.data.filter( - town => town.nomCommune.toLowerCase() === city.toLowerCase() - ) - return filteredResponse[0].codeCommune - } - } catch (error) { - log( - 'error', - `Query getInseeCode failed for postalCode ${postalCode} / ${city}` - ) - throw errors.USER_ACTION_NEEDED - } -} - -module.exports = { - getInseeCode, -} - - -/***/ }), -/* 1561 */ -/***/ ((module, __unused_webpack_exports, __webpack_require__) => { - -module.exports = __webpack_require__(1562); - -/***/ }), -/* 1562 */ -/***/ ((module, __unused_webpack_exports, __webpack_require__) => { - "use strict"; -var utils = __webpack_require__(1563); -var bind = __webpack_require__(1564); -var Axios = __webpack_require__(1565); -var mergeConfig = __webpack_require__(1593); -var defaults = __webpack_require__(1570); +var utils = __webpack_require__(1560); +var bind = __webpack_require__(1561); +var Axios = __webpack_require__(1562); +var mergeConfig = __webpack_require__(1590); +var defaults = __webpack_require__(1567); /** * Create an instance of Axios @@ -224124,14 +223979,14 @@ var axios = createInstance(defaults); axios.Axios = Axios; // Expose Cancel & CancelToken -axios.CanceledError = __webpack_require__(1583); -axios.CancelToken = __webpack_require__(1595); -axios.isCancel = __webpack_require__(1592); -axios.VERSION = (__webpack_require__(1588).version); -axios.toFormData = __webpack_require__(1574); +axios.CanceledError = __webpack_require__(1580); +axios.CancelToken = __webpack_require__(1592); +axios.isCancel = __webpack_require__(1589); +axios.VERSION = (__webpack_require__(1585).version); +axios.toFormData = __webpack_require__(1571); // Expose AxiosError class -axios.AxiosError = __webpack_require__(1572); +axios.AxiosError = __webpack_require__(1569); // alias for CanceledError for backward compatibility axios.Cancel = axios.CanceledError; @@ -224140,10 +223995,10 @@ axios.Cancel = axios.CanceledError; axios.all = function all(promises) { return Promise.all(promises); }; -axios.spread = __webpack_require__(1596); +axios.spread = __webpack_require__(1593); // Expose isAxiosError -axios.isAxiosError = __webpack_require__(1597); +axios.isAxiosError = __webpack_require__(1594); module.exports = axios; @@ -224152,13 +224007,13 @@ module.exports["default"] = axios; /***/ }), -/* 1563 */ +/* 1560 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var bind = __webpack_require__(1564); +var bind = __webpack_require__(1561); // utils is a library of generic helper functions non-specific to axios @@ -224629,7 +224484,7 @@ module.exports = { /***/ }), -/* 1564 */ +/* 1561 */ /***/ ((module) => { "use strict"; @@ -224647,19 +224502,19 @@ module.exports = function bind(fn, thisArg) { /***/ }), -/* 1565 */ +/* 1562 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); -var buildURL = __webpack_require__(1566); -var InterceptorManager = __webpack_require__(1567); -var dispatchRequest = __webpack_require__(1568); -var mergeConfig = __webpack_require__(1593); -var buildFullPath = __webpack_require__(1578); -var validator = __webpack_require__(1594); +var utils = __webpack_require__(1560); +var buildURL = __webpack_require__(1563); +var InterceptorManager = __webpack_require__(1564); +var dispatchRequest = __webpack_require__(1565); +var mergeConfig = __webpack_require__(1590); +var buildFullPath = __webpack_require__(1575); +var validator = __webpack_require__(1591); var validators = validator.validators; /** @@ -224814,13 +224669,13 @@ module.exports = Axios; /***/ }), -/* 1566 */ +/* 1563 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); function encode(val) { return encodeURIComponent(val). @@ -224891,13 +224746,13 @@ module.exports = function buildURL(url, params, paramsSerializer) { /***/ }), -/* 1567 */ +/* 1564 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); function InterceptorManager() { this.handlers = []; @@ -224952,17 +224807,17 @@ module.exports = InterceptorManager; /***/ }), -/* 1568 */ +/* 1565 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); -var transformData = __webpack_require__(1569); -var isCancel = __webpack_require__(1592); -var defaults = __webpack_require__(1570); -var CanceledError = __webpack_require__(1583); +var utils = __webpack_require__(1560); +var transformData = __webpack_require__(1566); +var isCancel = __webpack_require__(1589); +var defaults = __webpack_require__(1567); +var CanceledError = __webpack_require__(1580); /** * Throws a `CanceledError` if cancellation has been requested. @@ -225046,14 +224901,14 @@ module.exports = function dispatchRequest(config) { /***/ }), -/* 1569 */ +/* 1566 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); -var defaults = __webpack_require__(1570); +var utils = __webpack_require__(1560); +var defaults = __webpack_require__(1567); /** * Transform the data for a request or a response @@ -225075,17 +224930,17 @@ module.exports = function transformData(data, headers, fns) { /***/ }), -/* 1570 */ +/* 1567 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); -var normalizeHeaderName = __webpack_require__(1571); -var AxiosError = __webpack_require__(1572); -var transitionalDefaults = __webpack_require__(1573); -var toFormData = __webpack_require__(1574); +var utils = __webpack_require__(1560); +var normalizeHeaderName = __webpack_require__(1568); +var AxiosError = __webpack_require__(1569); +var transitionalDefaults = __webpack_require__(1570); +var toFormData = __webpack_require__(1571); var DEFAULT_CONTENT_TYPE = { 'Content-Type': 'application/x-www-form-urlencoded' @@ -225101,10 +224956,10 @@ function getDefaultAdapter() { var adapter; if (typeof XMLHttpRequest !== 'undefined') { // For browsers use XHR adapter - adapter = __webpack_require__(1575); + adapter = __webpack_require__(1572); } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') { // For node use HTTP adapter - adapter = __webpack_require__(1585); + adapter = __webpack_require__(1582); } return adapter; } @@ -225202,7 +225057,7 @@ var defaults = { maxBodyLength: -1, env: { - FormData: __webpack_require__(1589) + FormData: __webpack_require__(1586) }, validateStatus: function validateStatus(status) { @@ -225228,13 +225083,13 @@ module.exports = defaults; /***/ }), -/* 1571 */ +/* 1568 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); module.exports = function normalizeHeaderName(headers, normalizedName) { utils.forEach(headers, function processHeader(value, name) { @@ -225247,13 +225102,13 @@ module.exports = function normalizeHeaderName(headers, normalizedName) { /***/ }), -/* 1572 */ +/* 1569 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); /** * Create an Error with the specified message, config, error code, request and response. @@ -225340,7 +225195,7 @@ module.exports = AxiosError; /***/ }), -/* 1573 */ +/* 1570 */ /***/ ((module) => { "use strict"; @@ -225354,13 +225209,13 @@ module.exports = { /***/ }), -/* 1574 */ +/* 1571 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); /** * Convert a data object to FormData @@ -225433,23 +225288,23 @@ module.exports = toFormData; /***/ }), -/* 1575 */ +/* 1572 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); -var settle = __webpack_require__(1576); -var cookies = __webpack_require__(1577); -var buildURL = __webpack_require__(1566); -var buildFullPath = __webpack_require__(1578); -var parseHeaders = __webpack_require__(1581); -var isURLSameOrigin = __webpack_require__(1582); -var transitionalDefaults = __webpack_require__(1573); -var AxiosError = __webpack_require__(1572); -var CanceledError = __webpack_require__(1583); -var parseProtocol = __webpack_require__(1584); +var utils = __webpack_require__(1560); +var settle = __webpack_require__(1573); +var cookies = __webpack_require__(1574); +var buildURL = __webpack_require__(1563); +var buildFullPath = __webpack_require__(1575); +var parseHeaders = __webpack_require__(1578); +var isURLSameOrigin = __webpack_require__(1579); +var transitionalDefaults = __webpack_require__(1570); +var AxiosError = __webpack_require__(1569); +var CanceledError = __webpack_require__(1580); +var parseProtocol = __webpack_require__(1581); module.exports = function xhrAdapter(config) { return new Promise(function dispatchXhrRequest(resolve, reject) { @@ -225662,13 +225517,13 @@ module.exports = function xhrAdapter(config) { /***/ }), -/* 1576 */ +/* 1573 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var AxiosError = __webpack_require__(1572); +var AxiosError = __webpack_require__(1569); /** * Resolve or reject a Promise based on response status. @@ -225694,13 +225549,13 @@ module.exports = function settle(resolve, reject, response) { /***/ }), -/* 1577 */ +/* 1574 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); module.exports = ( utils.isStandardBrowserEnv() ? @@ -225754,14 +225609,14 @@ module.exports = ( /***/ }), -/* 1578 */ +/* 1575 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var isAbsoluteURL = __webpack_require__(1579); -var combineURLs = __webpack_require__(1580); +var isAbsoluteURL = __webpack_require__(1576); +var combineURLs = __webpack_require__(1577); /** * Creates a new URL by combining the baseURL with the requestedURL, @@ -225781,7 +225636,7 @@ module.exports = function buildFullPath(baseURL, requestedURL) { /***/ }), -/* 1579 */ +/* 1576 */ /***/ ((module) => { "use strict"; @@ -225802,7 +225657,7 @@ module.exports = function isAbsoluteURL(url) { /***/ }), -/* 1580 */ +/* 1577 */ /***/ ((module) => { "use strict"; @@ -225823,13 +225678,13 @@ module.exports = function combineURLs(baseURL, relativeURL) { /***/ }), -/* 1581 */ +/* 1578 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); // Headers whose duplicates are ignored by node // c.f. https://nodejs.org/api/http.html#http_message_headers @@ -225883,13 +225738,13 @@ module.exports = function parseHeaders(headers) { /***/ }), -/* 1582 */ +/* 1579 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); module.exports = ( utils.isStandardBrowserEnv() ? @@ -225958,14 +225813,14 @@ module.exports = ( /***/ }), -/* 1583 */ +/* 1580 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var AxiosError = __webpack_require__(1572); -var utils = __webpack_require__(1563); +var AxiosError = __webpack_require__(1569); +var utils = __webpack_require__(1560); /** * A `CanceledError` is an object that is thrown when an operation is canceled. @@ -225987,7 +225842,7 @@ module.exports = CanceledError; /***/ }), -/* 1584 */ +/* 1581 */ /***/ ((module) => { "use strict"; @@ -226000,26 +225855,26 @@ module.exports = function parseProtocol(url) { /***/ }), -/* 1585 */ +/* 1582 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); -var settle = __webpack_require__(1576); -var buildFullPath = __webpack_require__(1578); -var buildURL = __webpack_require__(1566); +var utils = __webpack_require__(1560); +var settle = __webpack_require__(1573); +var buildFullPath = __webpack_require__(1575); +var buildURL = __webpack_require__(1563); var http = __webpack_require__(80); var https = __webpack_require__(81); -var httpFollow = (__webpack_require__(1586).http); -var httpsFollow = (__webpack_require__(1586).https); +var httpFollow = (__webpack_require__(1583).http); +var httpsFollow = (__webpack_require__(1583).https); var url = __webpack_require__(63); var zlib = __webpack_require__(83); -var VERSION = (__webpack_require__(1588).version); -var transitionalDefaults = __webpack_require__(1573); -var AxiosError = __webpack_require__(1572); -var CanceledError = __webpack_require__(1583); +var VERSION = (__webpack_require__(1585).version); +var transitionalDefaults = __webpack_require__(1570); +var AxiosError = __webpack_require__(1569); +var CanceledError = __webpack_require__(1580); var isHttps = /https:?/; @@ -226431,7 +226286,7 @@ module.exports = function httpAdapter(config) { /***/ }), -/* 1586 */ +/* 1583 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { var url = __webpack_require__(63); @@ -226440,7 +226295,7 @@ var http = __webpack_require__(80); var https = __webpack_require__(81); var Writable = (__webpack_require__(82).Writable); var assert = __webpack_require__(91); -var debug = __webpack_require__(1587); +var debug = __webpack_require__(1584); // Create handlers that pass events from native requests var events = ["abort", "aborted", "connect", "error", "socket", "timeout"]; @@ -227035,7 +226890,7 @@ module.exports.wrap = wrap; /***/ }), -/* 1587 */ +/* 1584 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { var debug; @@ -227056,7 +226911,7 @@ module.exports = function () { /***/ }), -/* 1588 */ +/* 1585 */ /***/ ((module) => { module.exports = { @@ -227064,15 +226919,15 @@ module.exports = { }; /***/ }), -/* 1589 */ +/* 1586 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { // eslint-disable-next-line strict -module.exports = __webpack_require__(1590); +module.exports = __webpack_require__(1587); /***/ }), -/* 1590 */ +/* 1587 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { var CombinedStream = __webpack_require__(147); @@ -227085,7 +226940,7 @@ var fs = __webpack_require__(149); var Stream = (__webpack_require__(82).Stream); var mime = __webpack_require__(139); var asynckit = __webpack_require__(150); -var populate = __webpack_require__(1591); +var populate = __webpack_require__(1588); // Public API module.exports = FormData; @@ -227579,7 +227434,7 @@ FormData.prototype.toString = function () { /***/ }), -/* 1591 */ +/* 1588 */ /***/ ((module) => { // populates missing values @@ -227595,7 +227450,7 @@ module.exports = function(dst, src) { /***/ }), -/* 1592 */ +/* 1589 */ /***/ ((module) => { "use strict"; @@ -227607,13 +227462,13 @@ module.exports = function isCancel(value) { /***/ }), -/* 1593 */ +/* 1590 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); /** * Config-specific merge-function which creates a new config-object @@ -227714,14 +227569,14 @@ module.exports = function mergeConfig(config1, config2) { /***/ }), -/* 1594 */ +/* 1591 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var VERSION = (__webpack_require__(1588).version); -var AxiosError = __webpack_require__(1572); +var VERSION = (__webpack_require__(1585).version); +var AxiosError = __webpack_require__(1569); var validators = {}; @@ -227807,13 +227662,13 @@ module.exports = { /***/ }), -/* 1595 */ +/* 1592 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var CanceledError = __webpack_require__(1583); +var CanceledError = __webpack_require__(1580); /** * A `CancelToken` is an object that can be used to request cancellation of an operation. @@ -227933,7 +227788,7 @@ module.exports = CancelToken; /***/ }), -/* 1596 */ +/* 1593 */ /***/ ((module) => { "use strict"; @@ -227967,13 +227822,13 @@ module.exports = function spread(callback) { /***/ }), -/* 1597 */ +/* 1594 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { "use strict"; -var utils = __webpack_require__(1563); +var utils = __webpack_require__(1560); /** * Determines whether the payload is an error thrown by Axios @@ -227986,6 +227841,171 @@ module.exports = function isAxiosError(payload) { }; +/***/ }), +/* 1595 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +// @ts-check +const { log, errors } = __webpack_require__(1) +const { findUserPdl } = __webpack_require__(1596) +const { getInseeCode } = __webpack_require__(1597) + +/** + * Verify user identity + * @param {object} fields + * @param {string} baseUrl + * @param {string} apiAuthKey + * @param {string} loginUtilisateur + * @returns {Promise<User>} + */ +async function verifyUserIdentity( + fields, + baseUrl, + apiAuthKey, + loginUtilisateur +) { + const inseeCode = await getInseeCode(fields.postalCode, fields.city) + + const pdl = await findUserPdl( + `${baseUrl}/enedis_SDE_recherche-point/1.0`, + apiAuthKey, + loginUtilisateur, + fields.lastname, + fields.address, + fields.postalCode, + inseeCode + ) + + if (fields.pointId != pdl) { + log('error', 'PointId does not match') + throw errors.LOGIN_FAILED + } + + return { + lastname: fields.lastname, + firstname: fields.firstname, + pointId: fields.pointId, + inseeCode, + postalCode: fields.postalCode, + address: fields.address, + } +} + +module.exports = { verifyUserIdentity } + + +/***/ }), +/* 1596 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +// @ts-check +const { log, errors } = __webpack_require__(1) +const soapRequest = __webpack_require__(1331) +const { parseUserPdl, parseTags, parseValue } = __webpack_require__(1555) +const { rechercherPoint } = __webpack_require__(1556) +const xml2js = __webpack_require__(1513) + +/** + * @param {string} url + * @param {string} apiAuthKey + * @param {string} appLogin + * @param {string} name + * @param {string} address + * @param {string} postalCode + * @param {string} inseeCode + * @return {Promise<string | null>} User Pdl + */ +async function findUserPdl( + url, + apiAuthKey, + appLogin, + name, + address, + postalCode, + inseeCode +) { + log('info', 'Fetching user data') + const sgeHeaders = { + 'Content-Type': 'text/xml;charset=UTF-8', + apikey: apiAuthKey, + } + + const { response } = await soapRequest({ + url: url, + headers: sgeHeaders, + xml: rechercherPoint(appLogin, name, postalCode, inseeCode, address), + }).catch(err => { + log('error', 'rechercherPointResponse') + log('error', err) + throw errors.LOGIN_FAILED + }) + + const parsedReply = await xml2js.parseStringPromise(response.body, { + tagNameProcessors: [parseTags], + valueProcessors: [parseValue], + explicitArray: false, + }) + + try { + return parseUserPdl(parsedReply) + } catch (error) { + log('error', 'Error while parsing user PDL: ' + error) + log( + 'error', + `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}` + ) + throw errors.LOGIN_FAILED + } +} + +module.exports = { findUserPdl } + + +/***/ }), +/* 1597 */ +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +// @ts-check +const { default: axios } = __webpack_require__(1558) +const { log, errors } = __webpack_require__(1) + +const API_URL = 'https://apicarto.ign.fr/api/codes-postaux/communes' + +/** + * Return inseeCode given a postalCode + * @param {string} postalCode + * @param {string} [city] + * @return {Promise<string>} inseeCode + */ +async function getInseeCode(postalCode, city) { + try { + log('info', `Query getInseeCode for postalCode ${postalCode} / ${city}`) + const response = await axios.get(`${API_URL}/${postalCode}`) + + if (response.data.length === 1) { + return response.data[0].codeCommune + } else { + if (!city) throw errors.USER_ACTION_NEEDED + + const filteredResponse = response.data.filter( + town => town.nomCommune.toLowerCase() === city.toLowerCase() + ) + return filteredResponse[0].codeCommune + } + } catch (error) { + log( + 'error', + `Query getInseeCode failed for postalCode ${postalCode} / ${city}` + ) + throw errors.USER_ACTION_NEEDED + } +} + +module.exports = { + getInseeCode, +} + + /***/ }), /* 1598 */ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { @@ -228024,7 +228044,7 @@ async function activateContract( } const { response } = await soapRequest({ - url: url, + url: `${url}/enedis_SGE_CommandeCollectePublicationMesures/1.0`, headers: sgeHeaders, xml: commanderCollectePublicationMesures( appLogin, @@ -228049,7 +228069,12 @@ async function activateContract( try { return parseServiceId(parsedReply) } catch (error) { - log('error', 'Error whileactivating contract: ' + error) + log('error', 'Error while activating contract: ' + error) + log( + 'error', + `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}` + ) + //TODO: handle SGT4B8: Il existe déjà plusieurs demandes en cours sur le point ? throw errors.LOGIN_FAILED } } @@ -228067,7 +228092,7 @@ const soapRequest = __webpack_require__(1331) const { parseTags, parseValue, parseContracts } = __webpack_require__(1555) const { rechercherServicesSouscritsMesures } = __webpack_require__(1556) const xml2js = __webpack_require__(1513) -const { contractState } = __webpack_require__(1600) +const { contractState, contractLibelle } = __webpack_require__(1600) /** * @param {string} url @@ -228100,12 +228125,25 @@ async function verifyContract(url, apiAuthKey, appLogin, contractId, pointId) { }) try { - const currentContract = parseContracts(parsedReply)[0] - if (currentContract.etatCode === contractState.ACTIF) + const currentContracts = parseContracts(parsedReply)[0] + let currentContract = null + if (Array.isArray(currentContracts)) { + currentContract = parseContracts(parsedReply)[0] + } else { + currentContract = parseContracts(parsedReply) + } + if ( + currentContract.etatCode === contractState.ACTIF && + currentContract.serviceSouscritLibelle === contractLibelle.ACTIF + ) return currentContract.serviceSouscritId return null } catch (error) { log('error', 'Error while parsing user contract: ' + error) + log( + 'error', + `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}` + ) throw errors.LOGIN_FAILED } } @@ -228127,7 +228165,17 @@ const contractState = { ACTIF: 'ACTIF', } -module.exports = { contractState } +/** + * Enum for contractLibelle values. + * @readonly + * @enum {number} + */ +const contractLibelle = { + ACTIF: + 'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage', +} + +module.exports = { contractState, contractLibelle } /***/ }), @@ -228157,14 +228205,14 @@ async function terminateContract( pointId, serviceId ) { - log('info', 'activateContract') + log('info', 'terminateContract') const sgeHeaders = { 'Content-Type': 'text/xml;charset=UTF-8', apikey: apiAuthKey, } const { response } = await soapRequest({ - url: url, + url: `${url}/enedis_SGE_CommandeArretServiceSouscritMesures/1.0`, headers: sgeHeaders, xml: commanderArretServiceSouscritMesures( appLogin, @@ -228186,9 +228234,19 @@ async function terminateContract( try { // We don't need any action on reply for now + if (parsedReply.Envelope.Body.Fault) { + log( + 'error', + `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}` + ) + } return parsedReply } catch (error) { log('error', 'Error while parsing user contract termination: ' + error) + log( + 'error', + `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}` + ) throw errors.VENDOR_DOWN } } @@ -228244,6 +228302,10 @@ async function getContractStartDate(url, apiAuthKey, userLogin, pointId) { return parseContractStartDate(result) } catch (error) { log('error', 'Error while processing contract start date: ' + error) + log( + 'error', + `Enedis issue ${result.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${result.Envelope.Body.Fault.faultstring}` + ) throw errors.NOT_EXISTING_DIRECTORY } } @@ -228289,7 +228351,9 @@ module.exports = { getAccount, saveAccountData } function iSLocal() { return ( - process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'local' + process.env.NODE_ENV === 'development' || + process.env.NODE_ENV === 'local' || + process.env.NODE_ENV === 'standalone' ) } diff --git a/manifest.konnector b/manifest.konnector index ea10c3b..17bc04d 100644 --- a/manifest.konnector +++ b/manifest.konnector @@ -81,5 +81,6 @@ } } }, - "manifest_version": "2" + "manifest_version": "2", + "on_delete_account": "onDeleteAccount.js" } diff --git a/package.json b/package.json index eb3c5f8..3d76bd2 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ "start": "node ./src/index.js", "dev": "cozy-konnector-dev", "standalone": "cozy-konnector-standalone", + "onDeleteAccount:standalone": "cozy-konnector-standalone src/onDeleteAccount.js", + "onDeleteAccount": "cozy-konnector-dev src/onDeleteAccount.js", "test": "jest", "test:cov": "jest --coverage", "pretest": "npm run clean", -- GitLab