chore: add suport to xml request and response
parent
4ae9104454
commit
70f0fc992d
|
@ -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())
|
||||||
|
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
||||||
|
@ -289,8 +292,8 @@ const getCrms = async (req, res) => {
|
||||||
|
|
||||||
const webhook = async (req, res) => {
|
const webhook = async (req, res) => {
|
||||||
|
|
||||||
console.log('========> webhook req.body: ', JSON.stringify(req.body, null, 6))
|
console.log('========> webhook req.body: ', JSON.stringify(req.body, null, 6))
|
||||||
|
|
||||||
console.log('========> req.body: ', req.body)
|
console.log('========> req.body: ', req.body)
|
||||||
|
|
||||||
if (!req.body?.meta)
|
if (!req.body?.meta)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue