diff --git a/.vscode/settings.json b/.vscode/settings.json index a2794ac6286ae5ba81f965b862667b94a4aad422..11f23f13742cfb0099c5f9b420c12bd6c34fa8da 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,5 +18,16 @@ "titleBar.inactiveBackground": "#42b88399", "titleBar.inactiveForeground": "#15202b99" }, - "cSpell.words": ["enedissgegrandlyon", "grandlyon", "insee"] + "cSpell.words": [ + "apikey", + "backoffice", + "Derniere", + "Detaillees", + "enedissgegrandlyon", + "grandlyon", + "HISTO", + "insee", + "konnectors", + "maxpower" + ] } diff --git a/src/core/contractActivation.js b/src/core/contractActivation.js index 8c1370b0c19b1a91b555afbdc08ac43f2ce5653b..b716201c15ba1e53444dd3885ca5b3abdd1a4d0c 100644 --- a/src/core/contractActivation.js +++ b/src/core/contractActivation.js @@ -4,6 +4,7 @@ const soapRequest = require('easy-soap-request') const { parseTags, parseValue, parseServiceId } = require('../helpers/parsing') const { commanderCollectePublicationMesures } = require('../requests/sge') const xml2js = require('xml2js') +const Sentry = require('@sentry/node') /** * @param {string} url @@ -45,6 +46,7 @@ async function activateContract( }).catch(err => { log('error', 'commanderCollectePublicationMesures') log('error', err) + Sentry.captureException('commanderCollectePublicationMesures', err) throw errors.LOGIN_FAILED }) @@ -57,7 +59,9 @@ async function activateContract( try { return parseServiceId(parsedReply) } catch (error) { - log('error', 'Error while activating contract: ' + error) + const errorMessage = 'Error while activating contract: ' + error + log('error', errorMessage) + Sentry.captureException(errorMessage) if (parsedReply.Envelope.Body.Fault) { log( 'error', diff --git a/src/core/contractStartDate.js b/src/core/contractStartDate.js index 051d4edad9e2d795e056e08c63739fcbd594fc21..ff77cc1a1b08e33860e0071db3a249997d79916d 100644 --- a/src/core/contractStartDate.js +++ b/src/core/contractStartDate.js @@ -8,6 +8,7 @@ const { } = require('../helpers/parsing') const xml2js = require('xml2js') const { consulterDonneesTechniquesContractuelles } = require('../requests/sge') +const Sentry = require('@sentry/node') /** * Get user contract start date @@ -29,7 +30,9 @@ async function getContractStartDate(url, apiAuthKey, userLogin, pointId) { headers: sgeHeaders, xml: consulterDonneesTechniquesContractuelles(pointId, userLogin), }).catch(err => { - log('error', 'Error while fetching contract start date : ' + err) + const errorMessage = 'Error while fetching contract start date : ' + err + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.VENDOR_DOWN }) @@ -41,7 +44,9 @@ async function getContractStartDate(url, apiAuthKey, userLogin, pointId) { try { return parseContractStartDate(result) } catch (error) { - log('error', 'Error while processing contract start date: ' + error) + const errorMessage = 'Error while processing contract start date: ' + error + log('error', errorMessage) + Sentry.captureException(errorMessage) log( 'error', `Enedis issue ${result.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${result.Envelope.Body.Fault.faultstring}` diff --git a/src/core/contractTermination.js b/src/core/contractTermination.js index 4348e119ee0e3e743d1cee46dcaadcba2eecef17..692bc2affac9eac706c1de89b3d0477f557a7ded 100644 --- a/src/core/contractTermination.js +++ b/src/core/contractTermination.js @@ -4,6 +4,7 @@ const soapRequest = require('easy-soap-request') const { parseTags, parseValue } = require('../helpers/parsing') const { commanderArretServiceSouscritMesures } = require('../requests/sge') const xml2js = require('xml2js') +const Sentry = require('@sentry/node') /** * @param {string} url @@ -39,6 +40,7 @@ async function terminateContract( }).catch(err => { log('error', 'commanderArretServiceSouscritMesures') log('error', err) + Sentry.captureException('commanderArretServiceSouscritMesures', err) throw errors.VENDOR_DOWN }) @@ -58,8 +60,11 @@ async function terminateContract( } return parsedReply } catch (error) { - log('error', 'Error while parsing user contract termination: ' + error) + const errorMessage = + 'Error while parsing user contract termination: ' + error + log('error', errorMessage) log('error', `Enedis issue ${JSON.stringify(parsedReply.Envelope.Body)}`) + Sentry.captureException(errorMessage) throw errors.VENDOR_DOWN } } diff --git a/src/core/contractVerification.js b/src/core/contractVerification.js index d1a26069457f4fc3e8d5c1102ddc1601cd39340b..8bc1c6f2716567969268875f1472b77acf16d5c2 100644 --- a/src/core/contractVerification.js +++ b/src/core/contractVerification.js @@ -10,6 +10,7 @@ const { const { rechercherServicesSouscritsMesures } = require('../requests/sge') const xml2js = require('xml2js') const { contractState } = require('./types/enum') +const Sentry = require('@sentry/node') /** * @param {string} url @@ -32,6 +33,7 @@ async function verifyContract(url, apiAuthKey, appLogin, contractId, pointId) { }).catch(err => { log('error', 'rechercherServicesSouscritsMesures') log('error', err) + Sentry.captureException('rechercherServicesSouscritsMesures', err) throw errors.LOGIN_FAILED }) @@ -44,6 +46,7 @@ async function verifyContract(url, apiAuthKey, appLogin, contractId, pointId) { try { if (!checkContractExists(parsedReply)) { log('error', 'no contract found') + Sentry.captureException('no contract found') return null } @@ -61,7 +64,9 @@ async function verifyContract(url, apiAuthKey, appLogin, contractId, pointId) { return currentContract.serviceSouscritId return null } catch (error) { - log('error', 'Error while parsing user contract: ' + error) + const errorMessage = 'Error while parsing user contract: ' + error + log('error', errorMessage) + Sentry.captureException(errorMessage) if (parsedReply.Envelope.Body.Fault) { log( 'error', diff --git a/src/core/findUserAddress.js b/src/core/findUserAddress.js index 750db58620a5e9e1436e08b769ade6a19c2fba59..42e34887572b636a8799e11c241c885fbccd7185 100644 --- a/src/core/findUserAddress.js +++ b/src/core/findUserAddress.js @@ -8,6 +8,7 @@ const { } = require('../helpers/parsing') const xml2js = require('xml2js') const { consulterDonneesTechniquesContractuelles } = require('../requests/sge') +const Sentry = require('@sentry/node') /** * Get user contract start date @@ -19,6 +20,7 @@ const { consulterDonneesTechniquesContractuelles } = require('../requests/sge') */ async function findUserAddress(url, apiAuthKey, userLogin, pointId) { log('info', 'Fetching user address') + Sentry.captureMessage('Fetching user address') const sgeHeaders = { 'Content-Type': 'text/xml;charset=UTF-8', apikey: apiAuthKey, @@ -42,12 +44,16 @@ async function findUserAddress(url, apiAuthKey, userLogin, pointId) { try { return parseUserAddress(result) } catch (error) { - log('error', 'Error while processing user address: ' + error) + const errorMessage = 'Error while processing user address: ' + error + log('error', errorMessage) log( 'error', `Enedis issue ${result.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${result.Envelope.Body.Fault.faultstring}` ) + Sentry.captureException(errorMessage) throw errors.LOGIN_FAILED + } finally { + Sentry.captureException('Error while processing user address') } } diff --git a/src/core/findUserPdl.js b/src/core/findUserPdl.js index ff8d0ae5b940c8025eaf3e17d61cecfa09a62733..0e51a8ad52d82f04857d7b28079039ebe4cd23ae 100644 --- a/src/core/findUserPdl.js +++ b/src/core/findUserPdl.js @@ -4,6 +4,7 @@ const soapRequest = require('easy-soap-request') const { parseUserPdl, parseTags, parseValue } = require('../helpers/parsing') const { rechercherPoint } = require('../requests/sge') const xml2js = require('xml2js') +const Sentry = require('@sentry/node') /** * @param {string} url @@ -45,6 +46,7 @@ async function findUserPdl( }).catch(err => { log('error', 'rechercherPointResponse') log('error', err) + Sentry.captureException('rechercherPointResponse', err) throw errors.LOGIN_FAILED }) @@ -57,7 +59,9 @@ async function findUserPdl( try { return parseUserPdl(parsedReply) } catch (error) { - log('warn', 'Error while parsing user PDL: ' + error) + const errorMessage = 'Error while parsing user PDL: ' + error + log('warn', errorMessage) + Sentry.captureException(errorMessage) if (parsedReply.Envelope.Body.Fault) { log( 'warn', diff --git a/src/core/verifyUserIdentity.js b/src/core/verifyUserIdentity.js index ebb4bc8faa54a71bf79d63e3da1ce133b84bda9b..3baf0c570c4ca2df1e2aa7c8347ae569ffde6f3c 100644 --- a/src/core/verifyUserIdentity.js +++ b/src/core/verifyUserIdentity.js @@ -7,6 +7,7 @@ const { removeMultipleSpaces, removeAddressnumber, } = require('../helpers/parsing') +const Sentry = require('@sentry/node') /** * Verify user identity @@ -105,8 +106,10 @@ async function verifyUserIdentity( log('error', 'PointId does not match') if (isAlternateStart) { + Sentry.captureException('PointId does not match: Alternate start') throw errors.TERMS_VERSION_MISMATCH } else { + Sentry.captureException('PointId does not match') throw errors.LOGIN_FAILED } } diff --git a/src/helpers/account.js b/src/helpers/account.js index f92e1294aa0a4729e6b3a4bdf7ccc43d784034d6..e9d520ee26001c5e3b5da9cde98bad627f1546e0 100644 --- a/src/helpers/account.js +++ b/src/helpers/account.js @@ -1,12 +1,15 @@ const { log } = require('cozy-konnector-libs') const { isLocal } = require('./env') +const Sentry = require('@sentry/node') function getAccountId() { log('info', `getAccountId`) try { return JSON.parse(process.env.COZY_FIELDS).account } catch (err) { - throw new Error(`You must provide 'account' in COZY_FIELDS: ${err.message}`) + const errorMessage = `You must provide 'account' in COZY_FIELDS: ${err.message}` + Sentry.captureException(errorMessage) + throw new Error(errorMessage) } } @@ -18,7 +21,9 @@ function getAccountRev() { ? 'fakeAccountRev' : JSON.parse(process.env.COZY_FIELDS).account_rev } catch (err) { - throw new Error(`You must provide 'account' in COZY_FIELDS: ${err.message}`) + const errorMessage = `You must provide 'account' in COZY_FIELDS: ${err.message}` + Sentry.captureException(errorMessage) + throw new Error(errorMessage) } } @@ -34,9 +39,9 @@ function getAccountSecret() { ? JSON.parse(process.env.COZY_FIELDS) : JSON.parse(process.env.COZY_PARAMETERS).secret } catch (err) { - throw new Error( - `You must provide 'account-types' in COZY_PARAMETERS: ${err.message}` - ) + const errorMessage = `You must provide 'account-types' in COZY_PARAMETERS: ${err.message}` + Sentry.captureException(errorMessage) + throw new Error(errorMessage) } } module.exports = { getAccountId, getAccountRev, getAccountSecret } diff --git a/src/index.js b/src/index.js index e68415ca4dc842da7d312a5512f6165160fbbb11..2c4f8586ea1d418851cd356819434a72f8bfca4d 100644 --- a/src/index.js +++ b/src/index.js @@ -85,24 +85,6 @@ Sentry.init({ async function start(fields, cozyParameters) { log('info', 'Konnector configuration ...') log('info', `isManual execution: ${manualExecution}`) - log('info', `konnector version : ${version}`) - - // const transaction = Sentry.startTransaction({ - // op: 'test', - // name: 'My First Test Transaction', - // }) - - Sentry.captureEvent({ message: 'konnector launch 3' }) - - setTimeout(() => { - try { - test() - } catch (e) { - Sentry.captureException(e) - } finally { - // transaction.finish() - } - }, 99) const pointId = parseInt(fields.pointId) let baseUrl = fields.wso2BaseUrl @@ -130,7 +112,9 @@ async function start(fields, cozyParameters) { !boToken || !boBaseUrl ) { - log('error', `Missing configuration secrets`) + const errorMessage = 'Missing configuration secrets' + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.VENDOR_DOWN } @@ -146,6 +130,7 @@ async function start(fields, cozyParameters) { if (isFirstStart(await getAccount(ACCOUNT_ID))) { log('info', 'First start...') + Sentry.captureMessage('konnector first start') const user = await verifyUserIdentity(fields, baseUrl, apiAuthKey, sgeLogin) let consent = await createBoConsent( @@ -161,7 +146,7 @@ async function start(fields, cozyParameters) { user.hasBeenThroughtSafetyOnBoarding ) - // handle user contract start date in order to preperly request data + // handle user contract start date in order to properly request data const userContractstartDate = await getContractStartDate( baseUrl, apiAuthKey, @@ -213,6 +198,7 @@ async function start(fields, cozyParameters) { }) } else { log('info', 'Alternate start...') + Sentry.captureMessage('Alternate start') const accountData = await getAccount(ACCOUNT_ID) const userConsent = await getBoConsent( boBaseUrl, @@ -229,7 +215,9 @@ async function start(fields, cozyParameters) { ) if (!userConsent) { - log('error', 'No user consent found') + const errorMessage = 'No user consent found' + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.VENDOR_DOWN } @@ -295,10 +283,13 @@ async function deleteConsent( ) await deleteBoConsent(boBaseUrl, boToken, userConsent.ID || 0) } else { - log('error', `No service id retrieved from BO`) + const errorMessage = `No service id retrieved from BO` + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.VENDOR_DOWN } if (isConsentExpired) { + Sentry.captureException('Consent expired') throw errors.USER_ACTION_NEEDED_OAUTH_OUTDATED } throw errors.TERMS_VERSION_MISMATCH @@ -416,6 +407,7 @@ async function getMaxPowerData(url, apiAuthKey, userLogin, pointId) { }).catch(err => { log('error', 'getMaxPowerData') log('error', err) + Sentry.captureException('getMaxPowerDate') return err }) @@ -491,6 +483,7 @@ async function getDataHalfHour(url, apiAuthKey, userLogin, pointId) { }).catch(err => { log('error', 'consultationMesuresDetaillees half-hour') log('error', err) + Sentry.captureException('consultationMesuresDetaillees half-hour') return err }) @@ -515,6 +508,7 @@ function processData(doctype = 'com.grandlyon.enedis.day') { return async (err, result) => { if (err) { log('error', err) + Sentry.captureException('error while processing daily data') throw err } // Return only needed part of info @@ -539,7 +533,7 @@ function processData(doctype = 'com.grandlyon.enedis.day') { `No half-hour activated. Issue: ${result.Envelope.Body.Fault.faultstring}` ) } else { - log('warn', `Unkown error ${e}`) + log('warn', `Unknown error ${e}`) } } } @@ -562,7 +556,7 @@ async function storeData(data, doctype, filterKeys) { } /** - * Agregate data from daily data to monthly and yearly data + * Aggregate 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 @@ -606,7 +600,3 @@ function isFirstStart(account) { log('info', 'Konnector first start') return true } -function test() { - Sentry.captureException('capture exception inside test') - throw new Error('Function test not implemented.') -} diff --git a/src/onDeleteAccount.js b/src/onDeleteAccount.js index 8bdb05f556ae3a1ffb2ae4b47e8e5920a191cd60..658a7cd7310ff650f6722625a0811eb279f19804 100644 --- a/src/onDeleteAccount.js +++ b/src/onDeleteAccount.js @@ -13,6 +13,7 @@ require('moment-timezone') moment.locale('fr') // set the language moment.tz.setDefault('Europe/Paris') // set the timezone const { isLocal, isDev } = require('./helpers/env') +const Sentry = require('@sentry/node') async function onDeleteAccount() { log('info', 'Deleting account ...') @@ -64,17 +65,19 @@ async function onDeleteAccount() { ) } } else { - log('error', `No service id retrieved from BO`) + const errorMessage = `No service id retrieved from BO` + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.VENDOR_DOWN } } log('info', 'Deleting account succeed') } else { - log( - 'error', + const errorMessage = 'No account revision was found, something went wrong during the deletion of said account' - ) + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.VENDOR_DOWN } } @@ -84,10 +87,9 @@ onDeleteAccount().then( log('info', `onDeleteAccount: Successfully delete consent and account.`) }, err => { - log( - 'error', - `onDeleteAccount: An error occured during script: ${err.message}` - ) + const errorMessage = `onDeleteAccount: An error occurred during script: ${err.message}` + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.VENDOR_DOWN } ) diff --git a/src/requests/bo.js b/src/requests/bo.js index c4805cc9e441916046afb4a63e6462a3a6ae04aa..e3979c308247bead37cb6f60c2cd3405fdb504fa 100644 --- a/src/requests/bo.js +++ b/src/requests/bo.js @@ -1,6 +1,7 @@ // @ts-check const { log, errors } = require('cozy-konnector-libs') const { default: axios } = require('axios') +const Sentry = require('@sentry/node') /** * @param {number} pointID @@ -49,7 +50,9 @@ async function createBoConsent( ) return data } catch (e) { - log('error', `BO replied with ${e}`) + const errorMessage = `BO replied with ${e}` + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.MAINTENANCE } } @@ -84,7 +87,9 @@ async function updateBoConsent(url, token, consent, serviceId) { ) return data } catch (e) { - log('error', `BO replied with ${e}`) + const errorMessage = `BO replied with ${e}` + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.MAINTENANCE } } @@ -104,7 +109,9 @@ async function getBoConsent(url, token, boId) { const { data } = await axios.get(`${url}/consent/${boId}`, headers) return data } catch (e) { - log('error', `BO replied with ${e}`) + const errorMessage = `BO replied with ${e}` + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.MAINTENANCE } } @@ -127,7 +134,9 @@ async function deleteBoConsent(url, token, boId) { const { data } = await axios.delete(`${url}/consent/${boId}`, headers) return data } catch (e) { - log('error', `BO replied with ${e}`) + const errorMessage = `BO replied with ${e}` + log('error', errorMessage) + Sentry.captureException(errorMessage) throw errors.MAINTENANCE } }