2023-11-29 20:05:48 +00:00
|
|
|
|
|
|
|
const path = require('path')
|
|
|
|
const { StatusCodes } = require("http-status-codes")
|
|
|
|
const { createCRMContact,
|
|
|
|
sendMessageSocket,
|
|
|
|
mustContainProperties,
|
|
|
|
journaling,
|
2024-07-19 18:48:34 +00:00
|
|
|
ticketCRM,
|
2023-11-29 20:05:48 +00:00
|
|
|
findProperty,
|
|
|
|
journalingRequest,
|
|
|
|
createContact,
|
|
|
|
lookupContactByPhone,
|
|
|
|
templateValidator } = require('../utils')
|
|
|
|
const fs = require("fs")
|
|
|
|
const { URL } = require('url')
|
|
|
|
const { oauth2 } = require('../utils')
|
|
|
|
const { exchangeForTokens } = oauth2
|
|
|
|
const Company = require('../models/Company')
|
|
|
|
const CRM = require('../models/CRM')
|
|
|
|
const CustomError = require('../errors')
|
|
|
|
|
|
|
|
const contactCreate = async (req, res) => {
|
|
|
|
|
|
|
|
const { companyId, crmFirstName, crmLastName, crmPhone, crmEmail } = req.body
|
|
|
|
|
|
|
|
mustContainProperties(req, ['companyId', 'crmPhone',])
|
|
|
|
|
|
|
|
await createCRMContact(companyId, crmFirstName, crmPhone, crmEmail, crmLastName)
|
|
|
|
|
|
|
|
res.status(StatusCodes.OK).send()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const deleteCrm = async (req, res) => {
|
|
|
|
|
|
|
|
const { companyId, crmBaseURL } = req.body
|
|
|
|
|
|
|
|
mustContainProperties(req, ['companyId', 'crmBaseURL',])
|
|
|
|
|
|
|
|
const crm = await CRM.findOne({
|
|
|
|
companyId, crmBaseURL: new URL(crmBaseURL.trim()).hostname
|
|
|
|
})
|
|
|
|
|
|
|
|
if (crm) await crm.deleteOne()
|
|
|
|
|
|
|
|
res.status(StatusCodes.OK).send()
|
|
|
|
}
|
|
|
|
|
|
|
|
const deleteCompany = async (req, res) => {
|
|
|
|
|
|
|
|
const { companyId } = req.body
|
|
|
|
|
|
|
|
mustContainProperties(req, ['companyId',])
|
|
|
|
|
|
|
|
const company = await Company.findOne({ companyId, })
|
|
|
|
|
|
|
|
if (company) await company.deleteOne()
|
|
|
|
|
|
|
|
res.status(StatusCodes.OK).send()
|
|
|
|
}
|
|
|
|
|
|
|
|
const callJournaling = async (req, res) => {
|
|
|
|
|
2024-07-19 18:48:34 +00:00
|
|
|
const { companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName, operationStatus } = req.body
|
|
|
|
|
|
|
|
console.log('REQ.BODY CRM TEST: ', JSON.stringify(req.body, null, 6))
|
2023-11-29 20:05:48 +00:00
|
|
|
|
|
|
|
mustContainProperties(req, ['companyId', 'operation', 'crmPhone', 'crmAgent',])
|
|
|
|
|
2024-07-19 00:41:03 +00:00
|
|
|
// if (operation == 'inboundAnsweredCall' && !crmCallDuration)
|
|
|
|
// throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is inboundAnsweredCall`)
|
|
|
|
// if (operation == 'outboundAsweredCall' && !crmCallDuration)
|
|
|
|
// throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is outboundAsweredCall`)
|
2023-11-29 20:05:48 +00:00
|
|
|
|
2024-07-19 18:48:34 +00:00
|
|
|
if (operationStatus == "hangup")
|
|
|
|
await journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName)
|
|
|
|
else if (operationStatus == "answered") {
|
|
|
|
await ticketCRM(companyId, crmPhone, crmAgent, crmFirstName)
|
|
|
|
}
|
2023-11-29 20:05:48 +00:00
|
|
|
|
|
|
|
res.status(StatusCodes.OK).send()
|
2024-07-19 18:48:34 +00:00
|
|
|
}
|
|
|
|
|
2023-11-29 20:05:48 +00:00
|
|
|
const install = async (req, res) => {
|
|
|
|
|
|
|
|
const { authUrl, companyId } = req.query
|
|
|
|
|
|
|
|
// Store the authUrl in the session
|
|
|
|
req.session.authUrl = authUrl
|
|
|
|
|
|
|
|
res.redirect(authUrl)
|
|
|
|
}
|
|
|
|
|
|
|
|
const oauthCallBack = async (req, res) => {
|
|
|
|
|
|
|
|
const { code } = req.query
|
|
|
|
|
|
|
|
// Retrieve the stored authUrl from the session
|
|
|
|
const storedAuthUrl = req.session.authUrl
|
|
|
|
|
|
|
|
const parsedUrl = new URL(storedAuthUrl)
|
|
|
|
const clientId = parsedUrl.searchParams.get('client_id')
|
|
|
|
|
|
|
|
if (code) {
|
|
|
|
let crmOauth = await CRM.findOne({ 'crm.authentication.crmClientId': clientId })
|
|
|
|
crmOauth = crmOauth.toObject()
|
|
|
|
|
|
|
|
const authCodeProof = {
|
|
|
|
grant_type: 'authorization_code',
|
|
|
|
client_id: crmOauth.crm.authentication.crmClientId,
|
|
|
|
client_secret: crmOauth.crm.authentication.crmClientSecret,
|
|
|
|
redirect_uri: process.env.URL_OAUTH_CALLBACK,
|
|
|
|
code
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exchange the authorization code for an access token and refresh token
|
|
|
|
await exchangeForTokens(crmOauth, authCodeProof)
|
|
|
|
|
|
|
|
const url = `${process.env.URL_OAUTH_FRONTEND_SUCCESS_REDIRECT}?clientId=${encodeURIComponent(clientId)}`
|
|
|
|
|
|
|
|
return res.redirect(url)
|
|
|
|
// return res.redirect(process.env.URL_OAUTH_FRONTEND_SUCCESS_REDIRECT)
|
|
|
|
}
|
|
|
|
|
|
|
|
res.status(StatusCodes.OK).send()
|
|
|
|
}
|
|
|
|
|
|
|
|
const testTemplate = async (req, res) => {
|
|
|
|
|
|
|
|
const { clientId, companyId } = req.body
|
|
|
|
|
|
|
|
let crmOauth = await CRM.findOne({ 'crm.authentication.crmClientId': clientId, testing: true })
|
|
|
|
|
|
|
|
if (!crmOauth)
|
|
|
|
return res.status(StatusCodes.OK).send()
|
|
|
|
|
|
|
|
crmOauth = crmOauth.toObject()
|
|
|
|
|
|
|
|
const { crmPhoneTest } = crmOauth.crm.authentication
|
|
|
|
|
|
|
|
await templateValidator(crmPhoneTest, crmOauth.crm, companyId)
|
|
|
|
|
|
|
|
crmOauth = await CRM.findOne({ 'crm.authentication.crmClientId': clientId })
|
|
|
|
crmOauth.testing = false
|
|
|
|
await crmOauth.save()
|
|
|
|
|
|
|
|
res.status(StatusCodes.OK).send()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const uploadCrmConfig = async (req, res) => {
|
|
|
|
|
|
|
|
const { companyId, } = req.body
|
|
|
|
|
|
|
|
mustContainProperties(req, ['companyId',])
|
|
|
|
|
|
|
|
if (!req?.file)
|
|
|
|
throw new CustomError.BadRequestError(`The crm property file must be provided`)
|
|
|
|
|
|
|
|
const file = req.file
|
|
|
|
|
|
|
|
let newCrm = fs.readFileSync(file.path, "utf8")
|
|
|
|
|
|
|
|
newCrm = JSON.parse(newCrm)
|
|
|
|
|
|
|
|
const index = newCrm.crmRest.findIndex(rest => rest?.createContactRecord)
|
|
|
|
|
|
|
|
const crmBaseURL = new URL(newCrm.crmRest[index].createContactRecord.request.url.trim()).hostname
|
|
|
|
|
|
|
|
let company = await Company.findOne({ companyId })
|
|
|
|
|
|
|
|
if (!company) {
|
|
|
|
company = await Company.create({ companyId })
|
|
|
|
}
|
|
|
|
|
|
|
|
let crm = await CRM.findOne({ companyId, crmBaseURL })
|
|
|
|
|
|
|
|
if (crm) {
|
|
|
|
crm.testing = true
|
|
|
|
crm.crm = newCrm
|
|
|
|
await crm.save()
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
crm = await CRM.create({
|
|
|
|
crmBaseURL,
|
|
|
|
companyId: company.companyId,
|
|
|
|
company,
|
|
|
|
testing: true,
|
|
|
|
crm: newCrm
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fs.unlinkSync(file.path)
|
|
|
|
|
|
|
|
const { type, crmClientId, crmClientSecret, crmScopes, crmPhoneTest } = crm.crm.authentication
|
|
|
|
|
|
|
|
if (type == 'oauth2') {
|
|
|
|
|
|
|
|
const { request, body, response } = findProperty(crm.crm.crmRest, 'authorizationEndpoint')
|
|
|
|
|
|
|
|
let { url } = request
|
|
|
|
|
|
|
|
url = url.replace('crmClientId', crmClientId)
|
|
|
|
.replace('crmClientSecret', crmClientSecret)
|
|
|
|
.replace('crmScopes', crmScopes)
|
|
|
|
.replace('crmRedirectURI', process.env.URL_OAUTH_CALLBACK)
|
|
|
|
|
|
|
|
|
|
|
|
const authUrl = `http://localhost:6001/api/v1/crm/install?authUrl=${encodeURIComponent(url)}&companyId=${encodeURIComponent(companyId)}`
|
|
|
|
console.log('--------> authUrl: ', authUrl)
|
|
|
|
|
|
|
|
return res.status(StatusCodes.OK).json({ url: authUrl })
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
await templateValidator(crmPhoneTest, newCrm, companyId)
|
|
|
|
|
|
|
|
crm.testing = false
|
|
|
|
await crm.save()
|
|
|
|
}
|
|
|
|
|
|
|
|
res.status(StatusCodes.OK).send()
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
contactCreate,
|
|
|
|
uploadCrmConfig,
|
|
|
|
callJournaling,
|
|
|
|
oauthCallBack,
|
|
|
|
install,
|
|
|
|
deleteCrm,
|
|
|
|
deleteCompany,
|
2024-07-19 18:48:34 +00:00
|
|
|
testTemplate
|
2023-11-29 20:05:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|