From a09f82aac8a595aa8bf363637f0b115037263c5e Mon Sep 17 00:00:00 2001
From: Bastien Dumont <bdumont@grandlyon.com>
Date: Wed, 21 Feb 2024 14:51:52 +0100
Subject: [PATCH] throw vendor down when request is rejected

---
 src/core/contractActivation.js   |  3 +++
 src/core/contractTermination.js  |  3 +++
 src/core/contractVerification.js |  3 +++
 src/core/findUserAddress.js      |  3 +++
 src/core/findUserPdl.js          | 16 +++++++++++-----
 src/helpers/catch.js             | 18 ++++++++++++++++++
 src/index.js                     | 21 ++++++++++++++-------
 7 files changed, 55 insertions(+), 12 deletions(-)
 create mode 100644 src/helpers/catch.js

diff --git a/src/core/contractActivation.js b/src/core/contractActivation.js
index 465d6ef..6a93c62 100644
--- a/src/core/contractActivation.js
+++ b/src/core/contractActivation.js
@@ -5,6 +5,7 @@ const { parseTags, parseValue, parseServiceId } = require('../helpers/parsing')
 const { commanderCollectePublicationMesures } = require('../requests/sge')
 const xml2js = require('xml2js')
 const Sentry = require('@sentry/node')
+const { catchRequestReject } = require('../helpers/catch')
 
 /**
  * @param {string} url
@@ -59,6 +60,8 @@ async function activateContract(
     throw new Error(errors.CAPTCHA_RESOLUTION_FAILED)
   })
 
+  catchRequestReject(response.body)
+
   const parsedReply = await xml2js.parseStringPromise(response.body, {
     tagNameProcessors: [parseTags],
     valueProcessors: [parseValue],
diff --git a/src/core/contractTermination.js b/src/core/contractTermination.js
index 663278b..39862c1 100644
--- a/src/core/contractTermination.js
+++ b/src/core/contractTermination.js
@@ -5,6 +5,7 @@ const { parseTags, parseValue } = require('../helpers/parsing')
 const { commanderArretServiceSouscritMesures } = require('../requests/sge')
 const xml2js = require('xml2js')
 const Sentry = require('@sentry/node')
+const { catchRequestReject } = require('../helpers/catch')
 
 /**
  * @param {string} url
@@ -53,6 +54,8 @@ async function terminateContract(
     throw new Error(errors.VENDOR_DOWN)
   })
 
+  catchRequestReject(response.body)
+
   const parsedReply = await xml2js.parseStringPromise(response.body, {
     tagNameProcessors: [parseTags],
     valueProcessors: [parseValue],
diff --git a/src/core/contractVerification.js b/src/core/contractVerification.js
index bb35911..db53cb5 100644
--- a/src/core/contractVerification.js
+++ b/src/core/contractVerification.js
@@ -11,6 +11,7 @@ const { rechercherServicesSouscritsMesures } = require('../requests/sge')
 const xml2js = require('xml2js')
 const { contractState } = require('./types/enum')
 const Sentry = require('@sentry/node')
+const { catchRequestReject } = require('../helpers/catch')
 
 /**
  * @param {string} url
@@ -45,6 +46,8 @@ async function verifyContract(url, apiAuthKey, appLogin, contractId, pointId) {
     throw new Error(errors.CAPTCHA_RESOLUTION_FAILED)
   })
 
+  catchRequestReject(response.body)
+
   const parsedReply = await xml2js.parseStringPromise(response.body, {
     tagNameProcessors: [parseTags],
     valueProcessors: [parseValue],
diff --git a/src/core/findUserAddress.js b/src/core/findUserAddress.js
index 4f7b51d..f5b5465 100644
--- a/src/core/findUserAddress.js
+++ b/src/core/findUserAddress.js
@@ -9,6 +9,7 @@ const {
 const xml2js = require('xml2js')
 const { consulterDonneesTechniquesContractuelles } = require('../requests/sge')
 const Sentry = require('@sentry/node')
+const { catchRequestReject } = require('../helpers/catch')
 
 /**
  * Get user contract start date
@@ -43,6 +44,8 @@ async function findUserAddress(url, apiAuthKey, userLogin, pointId) {
     throw new Error(errors.VENDOR_DOWN)
   })
 
+  catchRequestReject(response.body)
+
   const result = await xml2js.parseStringPromise(response.body, {
     tagNameProcessors: [parseTags],
     valueProcessors: [parseValue],
diff --git a/src/core/findUserPdl.js b/src/core/findUserPdl.js
index 137a8cc..5ad83f8 100644
--- a/src/core/findUserPdl.js
+++ b/src/core/findUserPdl.js
@@ -5,6 +5,7 @@ const { parseUserPdl, parseTags, parseValue } = require('../helpers/parsing')
 const { rechercherPoint } = require('../requests/sge')
 const xml2js = require('xml2js')
 const Sentry = require('@sentry/node')
+const { catchRequestReject } = require('../helpers/catch')
 
 /**
  * @param {string} url
@@ -60,12 +61,17 @@ async function findUserPdl(
       throw new Error(errors.VENDOR_DOWN)
     })
 
-    const parsedReply = await xml2js.parseStringPromise(response.body, {
-      tagNameProcessors: [parseTags],
-      valueProcessors: [parseValue],
-      explicitArray: false,
-    })
+    catchRequestReject(response.body)
 
+    const parsedReply = await xml2js
+      .parseStringPromise(response.body, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+      .catch(error => {
+        log('error', 'Error while parsing XML: ' + error)
+      })
     try {
       return parseUserPdl(parsedReply)
     } catch (error) {
diff --git a/src/helpers/catch.js b/src/helpers/catch.js
new file mode 100644
index 0000000..7598f65
--- /dev/null
+++ b/src/helpers/catch.js
@@ -0,0 +1,18 @@
+const { log, errors } = require('cozy-konnector-libs')
+
+/**
+ * Throw a VENDOR_DOWN error if the response contains a  "Request Rejected"
+ * Enedis might send a 429 status but the F5 always transform it to a 200
+ * @param {string} response
+ * @example <html><head><title>Request Rejected</title></head>
+ * <body>The requested URL was rejected. Please consult with your administrator</body></html>
+ */
+function catchRequestReject(response) {
+  if (response.includes('Request Rejected')) {
+    log('debug', response.slice(0, 100))
+    log('error', 'Request Rejected')
+    throw new Error(errors.VENDOR_DOWN)
+  }
+}
+
+module.exports = { catchRequestReject }
diff --git a/src/index.js b/src/index.js
index 5ddd206..04c366d 100644
--- a/src/index.js
+++ b/src/index.js
@@ -43,6 +43,7 @@ const Sentry = require('@sentry/node')
 // eslint-disable-next-line
 const Tracing = require('@sentry/tracing') // Needed for tracking performance in Sentry
 const { version } = require('../package.json')
+const { catchRequestReject } = require('./helpers/catch')
 
 moment.locale('fr') // set the language
 moment.tz.setDefault('Europe/Paris') // set the timezone
@@ -398,6 +399,8 @@ async function getOffPeakHours(url, apiAuthKey, userLogin, pointId) {
     return err
   })
 
+  catchRequestReject(response.body)
+
   const result = await xml2js.parseStringPromise(response.body, {
     tagNameProcessors: [parseTags],
     valueProcessors: [parseValue],
@@ -426,14 +429,14 @@ async function getOffPeakHours(url, apiAuthKey, userLogin, pointId) {
 }
 
 /**
- * Get hour data
+ * Get daily data
  * @param {string} url
  * @param {string} apiAuthKey
  * @param {string} userLogin
  * @param {string} pointId
  */
 async function getData(url, apiAuthKey, userLogin, pointId) {
-  log('info', 'Fetching data')
+  log('info', 'Fetching daily data')
   const sgeHeaders = {
     'Content-Type': 'text/xml;charset=UTF-8',
     apikey: apiAuthKey,
@@ -459,6 +462,8 @@ async function getData(url, apiAuthKey, userLogin, pointId) {
     return err
   })
 
+  catchRequestReject(response.body)
+
   xml2js.parseString(
     response.body,
     {
@@ -502,6 +507,8 @@ async function getMaxPowerData(url, apiAuthKey, userLogin, pointId) {
     return err
   })
 
+  catchRequestReject(response.body)
+
   xml2js.parseString(
     response.body,
     {
@@ -521,7 +528,7 @@ async function getMaxPowerData(url, apiAuthKey, userLogin, pointId) {
  * @param {string} pointId
  */
 async function getDataHalfHour(url, apiAuthKey, userLogin, pointId) {
-  log('info', 'Fetching data')
+  log('info', 'Fetching half-hour data')
   const sgeHeaders = {
     'Content-Type': 'text/xml;charset=UTF-8',
     apikey: apiAuthKey,
@@ -562,6 +569,8 @@ async function getDataHalfHour(url, apiAuthKey, userLogin, pointId) {
       return err
     })
 
+    catchRequestReject(response.body)
+
     xml2js.parseString(
       response.body,
       {
@@ -579,7 +588,7 @@ async function getDataHalfHour(url, apiAuthKey, userLogin, pointId) {
  * @param {string} doctype
  * @returns
  */
-function processData(doctype = 'com.grandlyon.enedis.day') {
+function processData(doctype) {
   return async (err, result) => {
     if (err) {
       log('error', err)
@@ -587,7 +596,7 @@ function processData(doctype = 'com.grandlyon.enedis.day') {
       throw err
     }
     // Return only needed part of info
-    log('info', doctype)
+    log('info', `Processing ${doctype} data`)
     try {
       const data = parseSgeXmlData(result)
       const processedDailyData = await storeData(
@@ -595,8 +604,6 @@ function processData(doctype = 'com.grandlyon.enedis.day') {
         doctype,
         ['year', 'month', 'day', 'hour', 'minute']
       )
-
-      log('info', 'Aggregate enedis daily data for month and year')
       if (doctype === 'com.grandlyon.enedis.day') {
         log('info', 'Aggregating...')
         await aggregateMonthAndYearData(processedDailyData)
-- 
GitLab