chore: add suport to xml request and response

master
adriano 2024-10-04 14:59:10 -03:00
parent 4ae9104454
commit 70f0fc992d
5 changed files with 235 additions and 5 deletions

View File

@ -10,10 +10,24 @@ const express = require('express')
const app = express() const app = express()
const session = require('express-session') const session = require('express-session')
const bodyParser = require('body-parser'); // Para JSON
require('body-parser-xml')(bodyParser); // Para XML
// rest of the packages // rest of the packages
const morgan = require('morgan') const morgan = require('morgan')
// const fileUpload = require('express-fileupload') // const fileUpload = require('express-fileupload')
// Middleware para lidar com JSON
app.use(bodyParser.json());
// Middleware para lidar com XML
app.use(bodyParser.xml({
limit: '1MB',
xmlParseOptions: {
explicitArray: false,
}
}));
const rateLimiter = require('express-rate-limit') const rateLimiter = require('express-rate-limit')
// Swagger // Swagger
@ -51,7 +65,7 @@ app.use(cors())
app.use(xss()) app.use(xss())
app.use(morgan('tiny')) app.use(morgan('tiny'))
app.use(express.json()) // app.use(express.json())
// app.use(fileUpload()) // app.use(fileUpload())

View File

@ -18,6 +18,9 @@ const { exchangeForTokens } = oauth2
const Company = require('../models/Company') const Company = require('../models/Company')
const CRM = require('../models/CRM') const CRM = require('../models/CRM')
const CustomError = require('../errors') const CustomError = require('../errors')
const CRM_Contact = require('../models/CRM_Contact')
const axios = require('axios')
const { get, set } = require('../utils/redisClient')
const contactCreate = async (req, res) => { const contactCreate = async (req, res) => {
@ -324,6 +327,73 @@ const webhook = async (req, res) => {
res.status(StatusCodes.OK).send() res.status(StatusCodes.OK).send()
} }
const webhook_crm = async (req, res) => {
console.log('========> webhook crm req.body: ', JSON.stringify(req.body, null, 6))
const responseXml = `
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<notificationsResponse xmlns="urn:enterprise.soap.sforce.com">
<Ack>true</Ack>
</notificationsResponse>
</soapenv:Body>
</soapenv:Envelope>`
const sObject = req.body['soapenv:Envelope']['soapenv:Body']?.notifications?.Notification?.sObject
if (!sObject) {
res.set('Content-Type', 'text/xml')
return res.status(StatusCodes.OK).send(responseXml)
}
const whoId = sObject['sf:WhoId']
const EventSubtype = sObject['sf:EventSubtype']
const StartDateTime = sObject['sf:StartDateTime']
console.log('==========> crm EventSubtype: ', EventSubtype)
console.log('==========> crm StartDateTime: ', StartDateTime)
console.log('==========> crm StartDateTime timeStamp: ', timeStamp(StartDateTime))
if (EventSubtype == 'Event') {
const contact = await CRM_Contact.findOne({
companyId: "99",
crmBaseURL: 'nocompany-a9-dev-ed.develop.my.salesforce.com',
contactId: whoId
})
console.log('==========> crm whoId: ', whoId)
console.log('==========> crm contact: ', contact)
const { phone } = contact
const contactIdChatwoot = await getContactIdChatwoot(phone)
if (!contactIdChatwoot) {
res.set('Content-Type', 'text/xml')
return res.status(StatusCodes.OK).send(responseXml)
}
console.log('==========> crm contactIdChatwoot: ', contactIdChatwoot)
const ticketId = await createConversation(contactIdChatwoot)
console.log('==========> crm ticketId: ', ticketId)
await toggleConversationStatus({ "status": "snoozed", "snoozed_until": timeStamp(StartDateTime) }, ticketId)
}
res.set('Content-Type', 'text/xml')
return res.status(StatusCodes.OK).send(responseXml)
}
module.exports = { module.exports = {
contactCreate, contactCreate,
uploadCrmConfig, uploadCrmConfig,
@ -334,7 +404,87 @@ module.exports = {
deleteCompany, deleteCompany,
testTemplate, testTemplate,
getCrms, getCrms,
webhook webhook,
webhook_crm
}
async function getContactIdChatwoot(phone) {
const config = {
method: 'get',
url: `http://172.31.187.47:3333/api/v1/accounts/15/contacts/search?q=${phone}`,
headers: {
'api_access_token': 'WpeGuicvuQ3pyLvYQ11eAxxL'
}
}
try {
const { data } = await axios(config)
return data.payload[0].id
} catch (error) {
console.error(error)
}
}
async function createConversation(contact_id) {
const data = JSON.stringify({
"inbox_id": "2",
"contact_id": `${contact_id}`,
"status": "pending",
"team_id": "1"
})
const config = {
method: 'post',
url: 'http://172.31.187.47:3333/api/v1/accounts/15/conversations',
headers: {
'api_access_token': 'WpeGuicvuQ3pyLvYQ11eAxxL',
'Content-Type': 'application/json'
},
data: data
}
try {
const { data } = await axios(config)
return data.id
} catch (error) {
console.error(error)
}
}
async function toggleConversationStatus(payload, ticketId) {
const config = {
method: 'post',
url: `http://172.31.187.47:3333/api/v1/accounts/15/conversations/${ticketId}/toggle_status`,
headers: {
'api_access_token': 'WpeGuicvuQ3pyLvYQ11eAxxL',
'Content-Type': 'application/json'
},
data: JSON.stringify(payload)
}
try {
const response = await axios(config)
console.log(JSON.stringify(response.data))
} catch (error) {
console.error(error)
}
}
function timeStamp(dateTimeISO8601) {
const date = new Date(dateTimeISO8601)
date.setHours(date.getUTCHours() - 3)
const timestamp = date.getTime() / 1000
return timestamp
} }

View File

@ -10,6 +10,7 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"axios": "^1.6.1", "axios": "^1.6.1",
"body-parser-xml": "^2.0.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"express": "^4.17.1", "express": "^4.17.1",
@ -301,6 +302,17 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/body-parser-xml": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/body-parser-xml/-/body-parser-xml-2.0.5.tgz",
"integrity": "sha512-m1Kvr+0OVo1+t5hEgTrEQMIxFomck4682EJgFx4UpKcKVk9gViifgaFvSNwnQE+S10pPy8Q+dz9iWHYCol51Hw==",
"dependencies": {
"xml2js": "^0.5.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/boxen": { "node_modules/boxen": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
@ -2154,6 +2166,11 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
},
"node_modules/semver": { "node_modules/semver": {
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@ -2713,6 +2730,26 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/xml2js": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"engines": {
"node": ">=4.0"
}
},
"node_modules/xss-clean": { "node_modules/xss-clean": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/xss-clean/-/xss-clean-0.1.1.tgz", "resolved": "https://registry.npmjs.org/xss-clean/-/xss-clean-0.1.1.tgz",
@ -2981,6 +3018,14 @@
"type-is": "~1.6.17" "type-is": "~1.6.17"
} }
}, },
"body-parser-xml": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/body-parser-xml/-/body-parser-xml-2.0.5.tgz",
"integrity": "sha512-m1Kvr+0OVo1+t5hEgTrEQMIxFomck4682EJgFx4UpKcKVk9gViifgaFvSNwnQE+S10pPy8Q+dz9iWHYCol51Hw==",
"requires": {
"xml2js": "^0.5.0"
}
},
"boxen": { "boxen": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
@ -4377,6 +4422,11 @@
"sparse-bitfield": "^3.0.3" "sparse-bitfield": "^3.0.3"
} }
}, },
"sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
},
"semver": { "semver": {
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@ -4801,6 +4851,20 @@
"integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
"dev": true "dev": true
}, },
"xml2js": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
},
"xss-clean": { "xss-clean": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/xss-clean/-/xss-clean-0.1.1.tgz", "resolved": "https://registry.npmjs.org/xss-clean/-/xss-clean-0.1.1.tgz",

View File

@ -11,6 +11,7 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"axios": "^1.6.1", "axios": "^1.6.1",
"body-parser-xml": "^2.0.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"express": "^4.17.1", "express": "^4.17.1",

View File

@ -1,7 +1,7 @@
const express = require('express') const express = require('express')
const router = express.Router() const router = express.Router()
const { authorization, } = require('../middleware/authentication') const { authorization, } = require('../middleware/authentication')
const { contactCreate, testTemplate, uploadCrmConfig, callJournaling, oauthCallBack, install, deleteCrm, deleteCompany, getCrms, webhook } = require('../controllers/crmController') const { contactCreate, testTemplate, webhook_crm, uploadCrmConfig, callJournaling, oauthCallBack, install, deleteCrm, deleteCompany, getCrms, webhook } = require('../controllers/crmController')
const { fileUpload } = require("../utils") const { fileUpload } = require("../utils")
router.route('/create-contact').post(authorization, contactCreate) router.route('/create-contact').post(authorization, contactCreate)
@ -13,6 +13,7 @@ router.route('/oauth-callback').get(oauthCallBack)
router.route('/install').get(install) router.route('/install').get(install)
router.route('/test').post(testTemplate) router.route('/test').post(testTemplate)
router.route('/webhook').post(webhook) router.route('/webhook').post(webhook)
router.route('/webhook-crm').post(webhook_crm)
router.route('/:companyId').get(authorization, getCrms) router.route('/:companyId').get(authorization, getCrms)