Merge branch 'update_newtemper' into _dialogflow_omnihit_newtemper

pull/20/head
adriano 2023-08-08 14:47:28 -03:00
commit 69d99206e9
24 changed files with 2562 additions and 437 deletions

View File

@ -1,3 +1,7 @@
PORT=8019 PORT=8019
PORT_START=8020 PORT_START=8020
BASE_URL=http://localhost BASE_URL=http://localhost
PASS="strongpassword, strongpassword32"
DB_MONGO_URL=mongodb://localhost:27017
DB_MONGO_NAME=session_out_omnihit_db

View File

@ -1,45 +1,56 @@
const express = require('express'); const express = require('express')
const bodyparser = require('body-parser'); const bodyparser = require('body-parser')
const dotenv = require('dotenv'); const dotenv = require('dotenv')
dotenv.config({ path: '.env' }); dotenv.config({ path: '.env' })
const copyFolder = require('./helpers/copyFolder') const copyFolder = require('./helpers/copyFolder')
const createDir = require('./helpers/createDir') const createDir = require('./helpers/createDir')
const createFile = require('./helpers/createFile') const createFile = require('./helpers/createFile')
const path = require('path'); const path = require('path')
const db_info = require('./db_conn') const db_info = require('./db_conn')
const fs = require('fs'); const fs = require('fs')
let mysql_conn = require('./helpers/mysql_conn.js'); let mysql_conn = require('./helpers/mysql_conn.js')
const { exec, execSync, spawn } = require("child_process"); const { exec, execSync, spawn } = require('child_process')
const startPm2Process = require('./helpers/startPm2Process'); const startPm2Process = require('./helpers/startPm2Process')
const removeDir = require('./helpers/remove_dir'); const removeDir = require('./helpers/remove_dir')
const setSessionName = require('./helpers/setSessionNumber') const setSessionName = require('./helpers/setSessionNumber')
const getNumberFromName = require('./helpers/getNumberSequence') const getNumberFromName = require('./helpers/getNumberSequence')
const pm2 = require('pm2'); const pm2 = require('pm2')
const bcrypt = require('bcrypt')
const OmnihitDBConn = require('./model/db_conn')
const app = express(); const app = express()
app.use(bodyparser.json()); app.use(bodyparser.json())
app.get('/', function (req, res) { return res.send('Express + TypeScript Server'); }); app.get('/', function (req, res) {
return res.send('Express + TypeScript Server')
})
app.post('/api/session', async function (req, res) { app.post('/api/session', async function (req, res) {
let { app_name, whatsappId, client_url, number } = req.body let { app_name, whatsappId, client_url, number } = req.body
if(app_name){ if (app_name) {
app_name = app_name.trim() app_name = app_name.trim()
} }
console.log('__dirname: ', path.join(__dirname, '..', app_name)) console.log('__dirname: ', path.join(__dirname, '..', app_name))
console.log('app_name: ', app_name, ' | whatsappId: ', whatsappId, ' | client_url: ',client_url) console.log(
'app_name: ',
app_name,
' | whatsappId: ',
whatsappId,
' | client_url: ',
client_url
)
const sessionsPath = path.join(__dirname, '..', 'sessions') const sessionsPath = path.join(__dirname, '..', 'sessions')
const directoriesInDIrectory = fs.readdirSync(sessionsPath, { withFileTypes: true }) const directoriesInDIrectory = fs
.readdirSync(sessionsPath, { withFileTypes: true })
.filter((item) => item.isDirectory()) .filter((item) => item.isDirectory())
.map((item) => item.name); .map((item) => item.name)
console.log('directoriesInDIrectory: ', directoriesInDIrectory) console.log('directoriesInDIrectory: ', directoriesInDIrectory)
@ -48,146 +59,154 @@ app.post('/api/session', async function (req, res) {
let dirSessionsApp = path.join(sessionsPath, app_name) let dirSessionsApp = path.join(sessionsPath, app_name)
if (dirExist.length == 0) { if (dirExist.length == 0) {
let create = createDir(dirSessionsApp) let create = createDir(dirSessionsApp)
if (!create) { if (!create) {
res.status(500).json({ message: 'Cannot create the directory path!' }) res.status(500).json({ message: 'Cannot create the directory path!' })
return return
} }
} }
let appPort = [] let appPort = []
let existSubDir = false let existSubDir = false
for (let i = 0; i < directoriesInDIrectory.length; i++) { for (let i = 0; i < directoriesInDIrectory.length; i++) {
console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i]) console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i])
const subDir = fs.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), { withFileTypes: true }) const subDir = fs
.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), {
withFileTypes: true,
})
.filter((item) => item.isDirectory()) .filter((item) => item.isDirectory())
.map((item) => item.name); .map((item) => item.name)
for (let x = 0; x < subDir.length; x++) { for (let x = 0; x < subDir.length; x++) {
console.log('subdir: ', subDir[x]) console.log('subdir: ', subDir[x])
let whatsId = subDir[x].split('_')[0] let whatsId = subDir[x].split('_')[0]
if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) { if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) {
let currPath = path.join(
sessionsPath,
directoriesInDIrectory[i],
subDir[x]
)
let currPath = path.join(sessionsPath, directoriesInDIrectory[i], subDir[x]) console.log(
'PATH: ',
console.log('PATH: ', path.join(sessionsPath, directoriesInDIrectory[i], subDir[x])) path.join(sessionsPath, directoriesInDIrectory[i], subDir[x])
)
let oldNumber = subDir[x].split('_')[1] let oldNumber = subDir[x].split('_')[1]
// let sessionNum = subDir[x].split('_')[2]
// let sessionPort = subDir[x].split('_')[3]
// let newSessionAppName = `${whatsId}_${number}_${sessionNum}_${sessionPort}`
// let newPath = path.join(sessionsPath, directoriesInDIrectory[i], newSessionAppName)
// console.log(`number: ${number}\noldNumber: ${oldNumber}\nsessionNum: ${sessionNum}\nsessionPort: ${sessionPort}\nnewSessionAppName:${newSessionAppName}`)
if (oldNumber != number) { if (oldNumber != number) {
deletePm2Process(subDir[x], currPath) deletePm2Process(subDir[x], currPath)
removeDir(currPath) removeDir(currPath)
} } else {
else {
res.send('ok') res.send('ok')
return return
} }
// try {
// //
// fs.renameSync(currPath, newPath)
// console.log("Successfully renamed the directory.")
// const data = fs.readFileSync(path.join(`${newPath}`, '.env'), 'utf-8');
// // console.log('Data: ', data)
// const newValue = data.replace(`MOBILEUID=${oldNumber}`, `MOBILEUID=${number}`)
// fs.writeFileSync(path.join(`${newPath}`, '.env'), newValue, 'utf-8');
// if (oldNumber != number) {
// removeDir(path.join(newPath, '.wwebjs_auth'))
// }
// startPm2Process(newSessionAppName, 'app.js', newPath, sessionPort)
// } catch (err) {
// console.log(err)
// }
// res.send('ok')
// return
} }
appPort.push(+subDir[x].split('_')[3]) let auxPort = subDir[x].split('_')[3]
console.log('---------> appPort: '+appPort) console.log('---------> auxPort: ' + auxPort)
if (auxPort) {
auxPort = +auxPort.trim()
if (!isNaN(auxPort)) {
appPort.push(auxPort)
}
}
existSubDir = true existSubDir = true
} }
} }
appPort = existSubDir ? Math.max(...appPort) + 1 : process.env.PORT_START appPort = existSubDir ? Math.max(...appPort) + 1 : process.env.PORT_START
console.log('new port: ', appPort) console.log('new port: ', appPort)
let dirSessionAppName let dirSessionAppName
let numberSession = 1 let numberSession = 1
// const dirSessionsNumberAppDirectories = fs.readdirSync(dirSessionsApp, { withFileTypes: true }) let lstPass = process.env.PASS
// .filter((item) => item.isDirectory() && item.name.includes(`${number}`))
// .map((item) => item.name);
// console.log('dirSessionsNumberAppDirectories', dirSessionsNumberAppDirectories, ' | dirSessionsApp: ', dirSessionsApp) if (!lstPass) {
console.log('PASS VARIABLE NOT FOUND INTO .ENV!')
console.log('client_url: ', client_url) return res.send('OK')
let db = db_info.filter((e) => e.client_url == client_url)
if (db && db.length > 0) {
db = db[0].db_conf
} }
// if (dirSessionsNumberAppDirectories.length > 0) { let db_credentials
try {
db_credentials = await OmnihitDBConn.findOne({ client_url })
if (db && Object.keys(db).length > 0) { if (!db_credentials) {
db_credentials = new OmnihitDBConn({
client_url: client_url,
db_conf: {
DB: '',
DB_HOST: '',
DB_USER: '',
DB_PASS: '',
DB_PORT: '',
},
})
await db_credentials.save()
return res.send('ok')
}
} catch (error) {
console.log(error)
}
if (db_credentials && db_credentials.db_conf.DB.trim().length > 0) {
lstPass = lstPass.split(',')
let password = null
// password = await lstPass.find(
// async (pass) =>
// await bcrypt.compare(pass.trim(), db_credentials.db_conf.DB_PASS)
// )
for (let i = 0; i < lstPass.length; i++) {
const hasPass = await bcrypt.compare(
lstPass[i].trim(),
db_credentials.db_conf.DB_PASS
)
if (hasPass) {
password = lstPass[i].trim()
break
}
}
if (password) {
db_credentials.db_conf.DB_PASS = password
} else {
return res.send('ok')
}
}
if (
db_credentials.db_conf &&
Object.keys(db_credentials.db_conf).length > 0
) {
const whatsapp_numbers = await new Promise((resolve, reject) => { const whatsapp_numbers = await new Promise((resolve, reject) => {
mysql_conn(db).query('SELECT name FROM Whatsapps WHERE name LIKE ?', [`%${number}%`], (err, result) => { mysql_conn(db_credentials.db_conf).query(
'SELECT name FROM Whatsapps WHERE name LIKE ?',
[`%${number}%`],
(err, result) => {
if (err) { if (err) {
reject(err) reject(err)
} } else {
else {
resolve(result) resolve(result)
} }
}); }
)
}) })
console.log('whatsapp_numbers: ', whatsapp_numbers) console.log('whatsapp_numbers: ', whatsapp_numbers)
@ -195,11 +214,12 @@ app.post('/api/session', async function (req, res) {
let session_num = [] let session_num = []
if (whatsapp_numbers && whatsapp_numbers.length > 0) { if (whatsapp_numbers && whatsapp_numbers.length > 0) {
console.log('whatsapp_numbers.length: ', whatsapp_numbers.length) console.log('whatsapp_numbers.length: ', whatsapp_numbers.length)
if (whatsapp_numbers.length == 5) { if (whatsapp_numbers.length == 5) {
res.status(400).json({ message: 'Cannot create more than 4 sessions from the same number' }) res.status(400).json({
message: 'Cannot create more than 4 sessions from the same number',
})
return return
} }
@ -209,16 +229,21 @@ app.post('/api/session', async function (req, res) {
console.log('numbered_sessions: ', numbered_sessions) console.log('numbered_sessions: ', numbered_sessions)
session_num = numbered_sessions.map((e) => parseInt((e.name.split('->')[e.name.split('->').length - 1]).trim().match(/\d+/)[0])) session_num = numbered_sessions.map((e) =>
parseInt(
e.name
.split('->')
[e.name.split('->').length - 1].trim()
.match(/\d+/)[0]
)
)
console.log('session_num', session_num) console.log('session_num', session_num)
} }
let index = 1; let index = 1
while (index <= 4) { while (index <= 4) {
if (!session_num.includes(index)) { if (!session_num.includes(index)) {
console.log(index) console.log(index)
numberSession = index numberSession = index
@ -226,11 +251,8 @@ app.post('/api/session', async function (req, res) {
} }
index++ index++
} }
} }
// numberSession = Math.max(...session_number) + 1 // numberSession = Math.max(...session_number) + 1
console.log('Number session: ', numberSession) console.log('Number session: ', numberSession)
@ -239,61 +261,63 @@ app.post('/api/session', async function (req, res) {
dirSessionAppName = `${whatsappId}_${number}_${numberSession}_${appPort}` dirSessionAppName = `${whatsappId}_${number}_${numberSession}_${appPort}`
destDir = path.join(dirSessionsApp, dirSessionAppName) destDir = path.join(dirSessionsApp, dirSessionAppName)
originDir = path.join(__dirname, '..', 'whats') originDir = path.join(__dirname, '..', 'whats')
copyFolder(originDir, destDir) copyFolder(originDir, destDir)
if (
if (db && Object.keys(db).length > 0) { db_credentials.db_conf &&
Object.keys(db_credentials.db_conf).length > 0
console.log('kkkkkkkkkkkkkkk') ) {
console.log('***SUCCESS SEED DIRECTORY CREATED***')
let whatsName let whatsName
const whatsapp = await new Promise((resolve, reject) => { const whatsapp = await new Promise((resolve, reject) => {
mysql_conn(db_credentials.db_conf).query(
mysql_conn(db).query("SELECT name from Whatsapps where id = ?", [whatsappId], (err, result) => { 'SELECT name from Whatsapps where id = ?',
[whatsappId],
(err, result) => {
if (err) { if (err) {
reject(err) reject(err)
} } else {
else {
resolve(result) resolve(result)
} }
}); }
)
}) })
if (whatsapp[0]["name"].split('->').length > 0) { if (whatsapp[0]['name'].split('->').length > 0) {
whatsName = `${whatsapp[0]["name"].split('->')[0]} -> S${numberSession}` whatsName = `${whatsapp[0]['name'].split('->')[0]} -> S${numberSession}`
} } else {
else { whatsName = `${whatsapp[0]['name']} -> S${numberSession}`
whatsName = `${whatsapp[0]["name"]} -> S${numberSession}`
} }
console.log('whatsName: ', whatsName) console.log('whatsName: ', whatsName)
console.log(`url: ${process.env.BASE_URL}:${appPort}\n whatsname: ${whatsName}\n whatsappId: ${whatsappId}`) console.log(
`url: ${process.env.BASE_URL}:${appPort}\n whatsname: ${whatsName}\n whatsappId: ${whatsappId}`
)
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
mysql_conn(db).query("UPDATE Whatsapps SET url = ?, name = ? where id = ?", [`${process.env.BASE_URL}:${appPort}`, `${whatsName}`, whatsappId], mysql_conn(db_credentials.db_conf).query(
'UPDATE Whatsapps SET url = ?, name = ? where id = ?',
[`${process.env.BASE_URL}:${appPort}`, `${whatsName}`, whatsappId],
function (err, result) { function (err, result) {
if (err) { if (err) {
reject(err) reject(err)
console.log("===> ERROR: " + err); console.log('===> ERROR: ' + err)
} } else {
else {
resolve(result) resolve(result)
// console.log('RESULT: ', result) // console.log('RESULT: ', result)
} }
// else // else
// console.log('myslq result: ', result); // console.log('myslq result: ', result);
}); }
)
}) })
let whatsappName = `${number} - s${numberSession}` let whatsappName = `${number} - s${numberSession}`
@ -301,91 +325,84 @@ app.post('/api/session', async function (req, res) {
console.log('-------------- numberSession', numberSession) console.log('-------------- numberSession', numberSession)
if (whatsapp.length > 0) { if (whatsapp.length > 0) {
if (whatsapp[0]['name'].split(' ').length > 0) { if (whatsapp[0]['name'].split(' ').length > 0) {
whatsappName = `${
whatsappName = `${whatsapp[0]['name'].split(' ')[0]} - S${numberSession}` whatsapp[0]['name'].split(' ')[0]
} - S${numberSession}`
} }
} }
console.log('whatsapp: ', whatsapp) console.log('whatsapp: ', whatsapp)
console.log("whatsapp[0]['name']: ", whatsapp[0]['name']) console.log("whatsapp[0]['name']: ", whatsapp[0]['name'])
const keys = Object.keys(db); const keys = Object.keys(db_credentials.db_conf)
var stream = fs.createWriteStream(path.join(destDir, '.env')); var stream = fs.createWriteStream(path.join(destDir, '.env'))
stream.once('open', function (fd) { stream.once('open', function (fd) {
stream.write("# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE\n"); stream.write('# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE\n')
stream.write(`MOBILEUID=${number}\n`); stream.write(`MOBILEUID=${number}\n`)
stream.write(`MOBILENAME=${whatsappName}\n`); stream.write(`MOBILENAME=${whatsappName}\n`)
stream.write("\n"); stream.write('\n')
stream.write("# PORT NUMBER FOR THIS API\n"); stream.write('# PORT NUMBER FOR THIS API\n')
stream.write(`PORT=${appPort}\n`); stream.write(`PORT=${appPort}\n`)
stream.write("\n"); stream.write('\n')
stream.write("# URL FROM THE OMNIHIT BACKEND API\n"); stream.write('# URL FROM THE OMNIHIT BACKEND API\n')
stream.write(`CLIENT_URL=${client_url}\n`); stream.write(`CLIENT_URL=${client_url}\n`)
stream.write("\n"); stream.write('\n')
stream.write("# OMNIHIT DATABASE\n"); stream.write('# OMNIHIT DATABASE\n')
keys.forEach((key, index) => { keys.forEach((key, index) => {
stream.write(`${key}=${db[key]}\n`); stream.write(`${key}=${db_credentials.db_conf[key]}\n`)
}); })
stream.write("\n"); stream.write('\n')
stream.write(`# WHATSAPP ID OF THE TABLE Whatsapps FROM THE OMNIHIT DATABASE\n`);
stream.write(`WHATSAPP_ID=${whatsappId}`);
stream.end();
});
stream.write(
`# WHATSAPP ID OF THE TABLE Whatsapps FROM THE OMNIHIT DATABASE\n`
)
stream.write(`WHATSAPP_ID=${whatsappId}`)
stream.end()
})
console.log('----------------destDir: ', destDir) console.log('----------------destDir: ', destDir)
execSync(`npm install`, { cwd: destDir }, (error, stdout, stderr) => { execSync(`npm install`, { cwd: destDir }, (error, stdout, stderr) => {
if (error) { if (error) {
console.log(`error: ${error.message}`); console.log(`error: ${error.message}`)
return; return
} }
if (stderr) { if (stderr) {
console.log(`stderr: ${stderr}`); console.log(`stderr: ${stderr}`)
return; return
} }
console.log(`stdout: ${stdout}`); console.log(`stdout: ${stdout}`)
}); })
startPm2Process(dirSessionAppName, 'app.js', destDir, appPort) startPm2Process(dirSessionAppName, 'app.js', destDir, appPort)
} }
res.send("OK"); res.send('OK')
})
});
app.post('/api/session/edit', async function (req, res) { app.post('/api/session/edit', async function (req, res) {
const { app_name, whatsappId, client_url, number } = req.body const { app_name, whatsappId, client_url, number } = req.body
}) })
app.post('/api/session/del', async function (req, res) { app.post('/api/session/del', async function (req, res) {
let { whatsappId, app_name } = req.body let { whatsappId, app_name } = req.body
if(app_name){ if (app_name) {
app_name = app_name.trim() app_name = app_name.trim()
} }
const sessionsPath = path.join(__dirname, '..', 'sessions') const sessionsPath = path.join(__dirname, '..', 'sessions')
const directoriesInDIrectory = fs.readdirSync(sessionsPath, { withFileTypes: true }) const directoriesInDIrectory = fs
.readdirSync(sessionsPath, { withFileTypes: true })
.filter((item) => item.isDirectory()) .filter((item) => item.isDirectory())
.map((item) => item.name); .map((item) => item.name)
console.log('directoriesInDIrectory: ', directoriesInDIrectory) console.log('directoriesInDIrectory: ', directoriesInDIrectory)
@ -393,94 +410,95 @@ app.post('/api/session/del', async function (req, res) {
console.log('dirExist: ', dirExist) console.log('dirExist: ', dirExist)
if (dirExist.length == 0) if (dirExist.length == 0) res.send('ok')
res.send('ok')
for (let i = 0; i < directoriesInDIrectory.length; i++) { for (let i = 0; i < directoriesInDIrectory.length; i++) {
console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i]) console.log('directoriesInDIrectory[i]', directoriesInDIrectory[i])
const subDir = fs.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), { withFileTypes: true }) const subDir = fs
.readdirSync(path.join(sessionsPath, directoriesInDIrectory[i]), {
withFileTypes: true,
})
.filter((item) => item.isDirectory()) .filter((item) => item.isDirectory())
.map((item) => item.name); .map((item) => item.name)
for (let x = 0; x < subDir.length; x++) { for (let x = 0; x < subDir.length; x++) {
console.log('subdir: ', subDir[x]) console.log('subdir: ', subDir[x])
let whatsId = subDir[x].split('_')[0] let whatsId = subDir[x].split('_')[0]
if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) { if (whatsId == whatsappId && app_name == directoriesInDIrectory[i]) {
let currPath = path.join(
sessionsPath,
directoriesInDIrectory[i],
subDir[x]
)
let currPath = path.join(sessionsPath, directoriesInDIrectory[i], subDir[x]) deletePm2Process(subDir[x], currPath)
deletePm2Process(subDir[x], currPath);
console.log('currPath: ', currPath) console.log('currPath: ', currPath)
removeDir(currPath) removeDir(currPath)
return res.send('ok') return res.send('ok')
} }
} }
} }
res.send('ok') res.send('ok')
}) })
app.listen(process.env.PORT || 8003, function () { app.listen(process.env.PORT || 8003, function () {
console.log("\u26A1[server]: Server is running at Port ::: " + process.env.PORT || 8003); console.log(
}); '\u26A1[server]: Server is running at Port ::: ' + process.env.PORT || 8003
)
})
process.on('uncaughtException', function (err) { process.on('uncaughtException', function (err) {
console.error(' '); console.error(' ')
console.error('----- ' + (new Date).toUTCString() + ' ----------------------------------') console.error(
'----- ' + new Date().toUTCString() + ' ----------------------------------'
)
console.error('Erro uncaughtException: ', err.message) console.error('Erro uncaughtException: ', err.message)
console.error(err.stack) console.error(err.stack)
console.error(' '); console.error(' ')
return return
}); })
function deletePm2Process(process_name, currPath) { function deletePm2Process(process_name, currPath) {
pm2.connect(function (err) { pm2.connect(function (err) {
if (err) { if (err) {
console.error(err); console.error(err)
} }
pm2.list(function (err, processes) { pm2.list(function (err, processes) {
if (err) { if (err) {
console.error(err); console.error(err)
} }
processes.forEach(function (process) { processes.forEach(function (process) {
console.log('.........process.name: ', process.name)
console.log(".........process.name: ", process.name);
if (process.name === process_name) { if (process.name === process_name) {
execSync(`pm2 delete ${process_name} && pm2 save --force`, { cwd: currPath }, (error, stdout, stderr) => { execSync(
`pm2 delete ${process_name} && pm2 save --force`,
{ cwd: currPath },
(error, stdout, stderr) => {
if (error) { if (error) {
console.log(`error: ${error.message}`); console.log(`error: ${error.message}`)
return; return
} }
if (stderr) { if (stderr) {
console.log(`stderr: ${stderr}`); console.log(`stderr: ${stderr}`)
return; return
} }
console.log(`stdout: ${stdout}`); console.log(`stdout: ${stdout}`)
});
} }
)
}
})
}); pm2.disconnect()
})
pm2.disconnect(); })
});
});
} }

View File

@ -0,0 +1,11 @@
const mongoose = require('mongoose')
require('dotenv').config({ path: `${process.cwd()}/.env` })
async function main(){
await mongoose.connect(process.env.DB_MONGO_URL, { dbName: process.env.DB_MONGO_NAME })
console.log('Conectou ao Mongoose!')
}
main().catch((err)=>console.log(err))
module.exports = mongoose

View File

@ -0,0 +1,20 @@
const bcrypt = require('bcrypt')
// const pass = async () => {
// // create a password
// const salt = await bcrypt.genSalt(12)
// const passwordHash = await bcrypt.hash('7901228899', salt)
// console.log(passwordHash)
// }
// pass()
const passDec = async () => {
const _pass = await bcrypt.compare(
'strongpassword',
'$2b$12$PZ8N1jU77nnNUCCGyKTMNOi2QI7X/SgPsISVQfr.cQ/jgdx5Z7AqC'
)
console.log('_pass: ', _pass)
}
passDec()
console.log('process.cwd(): ', process.cwd())

View File

@ -0,0 +1,33 @@
const mongoose = require('../db/connMongo')
const { Schema } = mongoose
const OmnihitDBConn = mongoose.model(
'Omnihit_db_conn',
new Schema(
{
client_url: {
type: String,
},
db_conf: {
DB: {
type: String,
},
DB_HOST: {
type: String,
},
DB_USER: {
type: String,
},
DB_PASS: {
type: String,
},
DB_PORT: {
type: String,
},
},
},
{ timestamps: true }
)
)
module.exports = OmnihitDBConn

File diff suppressed because it is too large Load Diff

View File

@ -11,10 +11,12 @@
"author": "Adriano <adriano08andrade@hotmail.com>", "author": "Adriano <adriano08andrade@hotmail.com>",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bcrypt": "^5.1.0",
"body-parser": "^1.20.1", "body-parser": "^1.20.1",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"express": "^4.18.2", "express": "^4.18.2",
"fs-extra": "^11.1.0", "fs-extra": "^11.1.0",
"mongoose": "^7.4.0",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"nodemon": "^2.0.20", "nodemon": "^2.0.20",
"socket.io": "^4.5.4" "socket.io": "^4.5.4"

View File

@ -5,6 +5,8 @@ import AppError from "../errors/AppError";
import UpdateSettingService from "../services/SettingServices/UpdateSettingService"; import UpdateSettingService from "../services/SettingServices/UpdateSettingService";
import ListSettingsService from "../services/SettingServices/ListSettingsService"; import ListSettingsService from "../services/SettingServices/ListSettingsService";
import updateSettingTicket from "../services/SettingServices/UpdateSettingTicket";
import SettingTicket from "../models/SettingTicket";
export const index = async (req: Request, res: Response): Promise<Response> => { export const index = async (req: Request, res: Response): Promise<Response> => {
// if (req.user.profile !== "master") { // if (req.user.profile !== "master") {
@ -12,8 +14,37 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
// } // }
const settings = await ListSettingsService(); const settings = await ListSettingsService();
const outBusinessHours = await SettingTicket.findOne({
where: { key: "outBusinessHours" }
});
const ticketExpiration = await SettingTicket.findOne({
where: { key: "ticketExpiration" }
});
return res.status(200).json(settings); return res.status(200).json({ settings, outBusinessHours, ticketExpiration });
};
export const updateTicketSettings = async (
req: Request,
res: Response
): Promise<Response> => {
const { outBusinessHours, ticketExpiration } = req.body;
if (outBusinessHours && Object.keys(outBusinessHours).length > 0) {
await updateSettingTicket({
...outBusinessHours,
key: "outBusinessHours"
});
}
if (ticketExpiration && Object.keys(ticketExpiration).length > 0) {
await updateSettingTicket({
...ticketExpiration,
key: "ticketExpiration"
});
}
return res.status(200).json({ outBusinessHours, ticketExpiration });
}; };
export const update = async ( export const update = async (

View File

@ -17,6 +17,7 @@ import UserOnlineTime from "../models/UserOnlineTime";
import Dialogflow from "../models/Dialogflow"; import Dialogflow from "../models/Dialogflow";
import QueryItem from "../models/QueryItem"; import QueryItem from "../models/QueryItem";
import SettingTicket from "../models/SettingTicket";
// eslint-disable-next-line // eslint-disable-next-line
const dbConfig = require("../config/database"); const dbConfig = require("../config/database");
// import dbConfig from "../config/database"; // import dbConfig from "../config/database";
@ -40,7 +41,8 @@ const models = [
StatusChatEnd, StatusChatEnd,
UserOnlineTime, UserOnlineTime,
Dialogflow, Dialogflow,
QueryItem QueryItem,
SettingTicket
]; ];
sequelize.addModels(models); sequelize.addModels(models);

View File

@ -0,0 +1,46 @@
import { QueryInterface, DataTypes } from "sequelize"
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("SettingTickets", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
message: {
type: DataTypes.STRING,
allowNull: true
},
startTime: {
type: DataTypes.DATE,
allowNull: true
},
endTime: {
type: DataTypes.DATE,
allowNull: true
},
value: {
type: DataTypes.STRING,
allowNull: false
},
key: {
type: DataTypes.STRING,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("SettingTickets");
}
}

View File

@ -0,0 +1,34 @@
import { QueryInterface } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.bulkInsert(
"SettingTickets",
[
{
message: "",
startTime: new Date(),
endTime: new Date(),
value: "disabled",
key: "outBusinessHours",
createdAt: new Date(),
updatedAt: new Date()
},
{
message: "",
startTime: new Date(),
endTime: new Date(),
value: "disabled",
key: "ticketExpiration",
createdAt: new Date(),
updatedAt: new Date()
}
],
{}
);
},
down: (queryInterface: QueryInterface) => {
return queryInterface.bulkDelete("SettingTickets", {});
}
};

View File

@ -0,0 +1,84 @@
import SettingTicket from "../models/SettingTicket";
import ListTicketTimeLife from "../services/TicketServices/ListTicketTimeLife";
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
import BotIsOnQueue from "./BotIsOnQueue";
import {
format as _format,
isWithinInterval,
parse,
subMinutes
} from "date-fns";
import ptBR from "date-fns/locale/pt-BR";
import { splitDateTime } from "./SplitDateTime";
const fsPromises = require("fs/promises");
const fs = require("fs");
let timer: any;
const AutoCloseTickets = async () => {
try {
// const botInfo = await BotIsOnQueue('botqueue')
// if (!botInfo.userIdBot) return
const ticketExpiration = await SettingTicket.findOne({
where: { key: "ticketExpiration" }
});
if (ticketExpiration && ticketExpiration.value == "enabled") {
const startTime = splitDateTime(
new Date(
_format(new Date(ticketExpiration.startTime), "yyyy-MM-dd HH:mm:ss", {
locale: ptBR
})
)
);
const seconds = timeStringToSeconds(startTime.fullTime);
console.log("Ticket seconds: ", seconds);
let tickets: any = await ListTicketTimeLife({
timeseconds: seconds,
status: "open"
});
console.log("tickets: ", tickets);
for (let i = 0; i < tickets.length; i++) {
await UpdateTicketService({
ticketData: { status: "closed", statusChatEnd: "FINALIZADO" },
ticketId: tickets[i].ticket_id,
msg: ticketExpiration.message
});
}
}
} catch (error) {
console.log("There was an error on try close the bot tickets: ", error);
}
};
function timeStringToSeconds(timeString: any) {
const [hours, minutes, seconds] = timeString.split(":").map(Number);
return hours * 3600 + minutes * 60 + seconds;
}
const schedule = async () => {
try {
clearInterval(timer);
await AutoCloseTickets();
} catch (error) {
console.log("error on schedule: ", error);
} finally {
timer = setInterval(schedule, 60000);
}
};
timer = setInterval(schedule, 60000);
export default schedule;

View File

@ -0,0 +1,40 @@
import {
Table,
Column,
CreatedAt,
UpdatedAt,
Model,
PrimaryKey,
AutoIncrement
} from "sequelize-typescript";
@Table
class SettingTicket extends Model<SettingTicket> {
@PrimaryKey
@AutoIncrement
@Column
id: number;
@Column
message: string;
@Column
startTime: Date;
@Column
endTime: Date;
@Column
value: string;
@Column
key: string;
@CreatedAt
createdAt: Date;
@UpdatedAt
updatedAt: Date;
}
export default SettingTicket;

View File

@ -9,7 +9,15 @@ settingRoutes.get("/settings", SettingController.index);
// routes.get("/settings/:settingKey", isAuth, SettingsController.show); // routes.get("/settings/:settingKey", isAuth, SettingsController.show);
settingRoutes.put(
"/settings/ticket",
isAuth,
SettingController.updateTicketSettings
);
// change setting key to key in future // change setting key to key in future
settingRoutes.put("/settings/:settingKey", isAuth, SettingController.update); settingRoutes.put("/settings/:settingKey", isAuth, SettingController.update);
export default settingRoutes; export default settingRoutes;

View File

@ -12,6 +12,7 @@ import { loadContactsCache } from "./helpers/ContactsCache";
import "./helpers/CloseBotTickets"; import "./helpers/CloseBotTickets";
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache"; import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
import { delRestoreControllFile } from "./helpers/RestoreControll"; import { delRestoreControllFile } from "./helpers/RestoreControll";
import "./helpers/AutoCloseTickets";
import "./helpers/SchedulingNotifySendMessage" import "./helpers/SchedulingNotifySendMessage"
import axios from "axios"; import axios from "axios";

View File

@ -0,0 +1,35 @@
import AppError from "../../errors/AppError";
import SettingTicket from "../../models/SettingTicket";
interface Request {
key: string;
startTime: string;
endTime: string;
value: string;
message: string;
}
const updateSettingTicket = async ({
key,
startTime,
endTime,
value,
message
}: Request): Promise<SettingTicket | undefined> => {
try {
const businessHours = await SettingTicket.findOne({ where: { key } });
if (!businessHours) {
throw new AppError("ERR_NO_SETTING_FOUND", 404);
}
await businessHours.update({ startTime, endTime, message, value });
return businessHours;
} catch (error: any) {
console.error("===> Error on UpdateSettingService.ts file: \n", error);
throw new AppError(error.message);
}
};
export default updateSettingTicket;

View File

@ -63,7 +63,7 @@ const UpdateTicketService = async ({
await ticket.reload(); await ticket.reload();
if (msg.length > 0) { if (msg?.trim().length > 0) {
setTimeout(async () => { setTimeout(async () => {

View File

@ -81,6 +81,14 @@ import { setMessageAsRead } from "../../helpers/SetMessageAsRead";
import FindOrCreateQueryItemService from "../SLM/FindOrCreateQueryItemService"; import FindOrCreateQueryItemService from "../SLM/FindOrCreateQueryItemService";
import ShowQueryItemService from "../SLM/ShowQueryItemService"; import ShowQueryItemService from "../SLM/ShowQueryItemService";
import QueryItem from "../../models/QueryItem"; import QueryItem from "../../models/QueryItem";
import SettingTicket from "../../models/SettingTicket"
import {
format as _format,
isWithinInterval,
parse,
subMinutes
} from "date-fns";
var lst: any[] = getWhatsappIds(); var lst: any[] = getWhatsappIds();
@ -914,6 +922,21 @@ const handleMessage = async (msg: any, wbot: any): Promise<void> => {
// let groupContact: Contact | undefined; // let groupContact: Contact | undefined;
if (msg.fromMe) { if (msg.fromMe) {
const ticketExpiration = await SettingTicket.findOne({
where: { key: "ticketExpiration" }
});
if (
ticketExpiration &&
ticketExpiration.value == "enabled" &&
ticketExpiration?.message.trim() == msg.body.trim()
) {
console.log("*********** TICKET EXPIRATION");
return;
}
// console.log('FROM ME: ', msg.fromMe, ' | /\u200e/.test(msg.body[0]: ', (/\u200e/.test(msg.body[0]))) // console.log('FROM ME: ', msg.fromMe, ' | /\u200e/.test(msg.body[0]: ', (/\u200e/.test(msg.body[0])))
// messages sent automatically by wbot have a special character in front of it // messages sent automatically by wbot have a special character in front of it
@ -1206,11 +1229,85 @@ const handleMessage = async (msg: any, wbot: any): Promise<void> => {
if (msg && !msg.fromMe && ticket.status == "pending") { if (msg && !msg.fromMe && ticket.status == "pending") {
await setMessageAsRead(ticket); await setMessageAsRead(ticket);
} }
const businessTime: any = await BusinessTime();
if (
msg.fromMe &&
businessTime &&
!businessTime.isWithinRange &&
businessTime.message.trim() == msg.body.trim()
) {
console.log("BUSINESS TIME OUT");
return;
}
if (!businessTime.isWithinRange && businessTime.message.trim().length > 0) {
botSendMessage(ticket, businessTime.message);
}
} catch (err) { } catch (err) {
Sentry.captureException(err); Sentry.captureException(err);
console.log("xxxxxxxxxxxxx err: ", err); console.log("xxxxxxxxxxxxx err: ", err);
logger.error(`Error handling whatsapp message: Err: ${err}`); logger.error(`Error handling whatsapp message: Err: ${err}`);
} }
async function BusinessTime() {
const outBusinessHours = await SettingTicket.findOne({
where: { key: "outBusinessHours" }
});
let isWithinRange = false;
if (outBusinessHours && outBusinessHours.value == "enabled") {
const ticketDateTimeUpdate = splitDateTime(
new Date(
_format(new Date(), "yyyy-MM-dd HH:mm:ss", {
locale: ptBR
})
)
);
const startTime = splitDateTime(
new Date(
_format(new Date(outBusinessHours.startTime), "yyyy-MM-dd HH:mm:ss", {
locale: ptBR
})
)
);
const endTime = splitDateTime(
new Date(
_format(new Date(outBusinessHours.endTime), "yyyy-MM-dd HH:mm:ss", {
locale: ptBR
})
)
);
const format = "HH:mm:ss";
const parsedStartTime = parse(
ticketDateTimeUpdate.fullTime,
format,
new Date()
);
const parsedEndTime = parse(startTime.fullTime, format, new Date());
const parsedTimeToCheck = parse(endTime.fullTime, format, new Date());
const timeInterval = { start: parsedStartTime, end: parsedEndTime };
// If the time range spans across different days, handle the date part
if (parsedEndTime < parsedStartTime) {
const nextDay = new Date(parsedStartTime);
nextDay.setDate(nextDay.getDate() + 1);
timeInterval.end = nextDay;
}
isWithinRange = isWithinInterval(parsedTimeToCheck, timeInterval);
console.log("Is the time within the range?", isWithinRange);
return { isWithinRange, message: outBusinessHours.message };
}
}
}; };
const handleMsgAck = async (msg_id: any, ack: any) => { const handleMsgAck = async (msg_id: any, ack: any) => {

View File

@ -20,6 +20,7 @@
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
"emoji-mart": "^3.0.1", "emoji-mart": "^3.0.1",
"formik": "^2.2.0", "formik": "^2.2.0",
"formik-material-ui-pickers": "^1.0.0-alpha.1",
"i18next": "^19.8.2", "i18next": "^19.8.2",
"i18next-browser-languagedetector": "^6.0.1", "i18next-browser-languagedetector": "^6.0.1",
"js-file-download": "^0.4.12", "js-file-download": "^0.4.12",

View File

@ -0,0 +1,304 @@
import React, { useState, useEffect, } from 'react'
// import * as Yup from 'yup'
import { Formik, Form, Field, } from 'formik'
import { toast } from 'react-toastify'
import { makeStyles } from '@material-ui/core/styles'
import { green } from '@material-ui/core/colors'
import { TimePicker } from 'formik-material-ui-pickers'
import DateFnsUtils from '@date-io/date-fns'
import ptBrLocale from "date-fns/locale/pt-BR"
import {
MuiPickersUtilsProvider,
} from '@material-ui/pickers'
import {
Dialog,
DialogContent,
DialogTitle,
Button,
DialogActions,
CircularProgress,
TextField,
Switch,
FormControlLabel,
} from '@material-ui/core'
import api from '../../services/api'
import { i18n } from '../../translate/i18n'
import toastError from '../../errors/toastError'
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
flexWrap: 'wrap',
},
multFieldLine: {
display: 'flex',
'& > *:not(:last-child)': {
marginRight: theme.spacing(1),
},
},
btnWrapper: {
position: 'relative',
},
buttonProgress: {
color: green[500],
position: 'absolute',
top: '50%',
left: '50%',
marginTop: -12,
marginLeft: -12,
},
}))
// const SessionSchema = Yup.object().shape({
// name: Yup.string()
// .min(2, 'Too Short!')
// .max(100, 'Too Long!')
// .required('Required'),
// })
const ConfigModal = ({ open, onClose, change }) => {
const classes = useStyles()
const initialState = {
startTimeBus: new Date(),
endTimeBus: new Date(),
messageBus: '',
businessTimeEnalbe: false,
ticketTimeExpiration: new Date(),
ticketExpirationMsg: '',
ticketExpirationEnable: false,
}
const [config, setConfig] = useState(initialState)
useEffect(() => {
const fetchSession = async () => {
try {
const { data } = await api.get('/settings')
setConfig({
startTimeBus: data.outBusinessHours.startTime,
endTimeBus: data.outBusinessHours.endTime,
messageBus: data.outBusinessHours.message,
businessTimeEnalbe: data.outBusinessHours.value === 'enabled' ? true : false,
ticketTimeExpiration: data.ticketExpiration.startTime,
ticketExpirationMsg: data.ticketExpiration.message,
ticketExpirationEnable: data.ticketExpiration.value === 'enabled' ? true : false
})
} catch (err) {
toastError(err)
}
}
fetchSession()
}, [change])
const handleSaveConfig = async (values) => {
values = {
outBusinessHours: {
startTime: values.startTimeBus,
endTime: values.endTimeBus,
message: values.messageBus,
value: values.businessTimeEnalbe ? 'enabled' : 'disabled'
},
ticketExpiration: {
startTime: values.ticketTimeExpiration,
message: values.ticketExpirationMsg,
value: values.ticketExpirationEnable ? 'enabled' : 'disabled'
}
}
try {
await api.put(`/settings/ticket`, values)
toast.success('Atualização realizada com sucesso!')
handleClose()
} catch (err) {
toastError(err)
}
}
const handleClose = () => {
onClose()
// setConfig(initialState)
}
return (
<div className={classes.root}>
<Dialog
open={open}
onClose={handleClose}
maxWidth="sm"
fullWidth
scroll="paper"
>
<DialogTitle>
Configurações
</DialogTitle>
<Formik
initialValues={config}
enableReinitialize={true}
// validationSchema={SessionSchema}
onSubmit={(values, actions) => {
setTimeout(() => {
handleSaveConfig(values)
actions.setSubmitting(false)
}, 100)
}}
>
{({ values, touched, errors, isSubmitting }) => (
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<Form>
<DialogContent dividers>
<div className={classes.multFieldLine}>
<Field
component={TimePicker}
name="startTimeBus"
label="Inicio atendimento"
ampm={false}
openTo="hours"
views={['hours', 'minutes',]}
format="HH:mm"
/>
{' '}
<Field
component={TimePicker}
name="endTimeBus"
label="Fim atendimento"
ampm={false}
openTo="hours"
views={['hours', 'minutes',]}
format="HH:mm"
/>
<FormControlLabel
control={
<Field
as={Switch}
color="primary"
name="businessTimeEnalbe"
checked={values.businessTimeEnalbe}
/>
}
label={'Ativar/Desativar'} />
</div>
<div>
<Field
as={TextField}
label={'Mensagem fora do horário de atendimento'}
type="messageBus"
multiline
rows={5}
fullWidth
name="messageBus"
error={
touched.messageBus && Boolean(errors.messageBus)
}
helperText={
touched.messageBus && errors.messageBus
}
variant="outlined"
margin="dense"
/>
</div>
<br />
<div className={classes.multFieldLine}>
<Field
component={TimePicker}
name="ticketTimeExpiration"
label="Ticket expira em hh:mm"
ampm={false}
openTo="hours"
views={['hours', 'minutes',]}
format="HH:mm"
/>
<FormControlLabel
control={
<Field
as={Switch}
color="primary"
name="ticketExpirationEnable"
checked={values.ticketExpirationEnable}
/>
}
label={'Ativar/Desativar'}
/>
</div>
<div>
<Field
as={TextField}
label={'Mensagem por falta de atividade no atendimento'}
type="ticketExpirationMsg"
multiline
rows={5}
fullWidth
name="ticketExpirationMsg"
error={
touched.ticketExpirationMsg && Boolean(errors.ticketExpirationMsg)
}
helperText={
touched.ticketExpirationMsg && errors.ticketExpirationMsg
}
variant="outlined"
margin="dense"
/>
</div>
</DialogContent>
<DialogActions>
<Button
onClick={handleClose}
color="secondary"
disabled={isSubmitting}
variant="outlined"
>
{i18n.t('whatsappModal.buttons.cancel')}
</Button>
<Button
type="submit"
color="primary"
disabled={isSubmitting}
variant="contained"
className={classes.btnWrapper}
>
{isSubmitting ? (
<CircularProgress
size={24}
className={classes.buttonProgress}
/>
) : 'Salvar'}
</Button>
</DialogActions>
</Form>
</MuiPickersUtilsProvider>
)}
</Formik>
</Dialog>
</div>
)
}
export default React.memo(ConfigModal)

View File

@ -76,7 +76,7 @@ const useAuth = () => {
const fetchSession = async () => { const fetchSession = async () => {
try { try {
const { data } = await api.get('/settings') const { data } = await api.get('/settings')
setSetting(data) setSetting(data.settings)
} catch (err) { } catch (err) {
toastError(err) toastError(err)
} }

View File

@ -6,6 +6,9 @@ import openSocket from 'socket.io-client'
import { makeStyles } from '@material-ui/core/styles' import { makeStyles } from '@material-ui/core/styles'
import { green } from '@material-ui/core/colors' import { green } from '@material-ui/core/colors'
import Settings from "@material-ui/icons/Settings";
import { import {
Button, Button,
TableBody, TableBody,
@ -47,6 +50,7 @@ import toastError from '../../errors/toastError'
//-------- //--------
import { AuthContext } from '../../context/Auth/AuthContext' import { AuthContext } from '../../context/Auth/AuthContext'
import { Can } from '../../components/Can' import { Can } from '../../components/Can'
import ConfigModal from '../../components/ConfigModal'
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
mainPaper: { mainPaper: {
@ -107,6 +111,7 @@ const Connections = () => {
const { whatsApps, loading } = useContext(WhatsAppsContext) const { whatsApps, loading } = useContext(WhatsAppsContext)
const [whatsAppModalOpen, setWhatsAppModalOpen] = useState(false) const [whatsAppModalOpen, setWhatsAppModalOpen] = useState(false)
const [configModalOpen, setConfigModalOpen] = useState(false)
const [qrModalOpen, setQrModalOpen] = useState(false) const [qrModalOpen, setQrModalOpen] = useState(false)
const [selectedWhatsApp, setSelectedWhatsApp] = useState(null) const [selectedWhatsApp, setSelectedWhatsApp] = useState(null)
const [confirmModalOpen, setConfirmModalOpen] = useState(false) const [confirmModalOpen, setConfirmModalOpen] = useState(false)
@ -134,7 +139,7 @@ const Connections = () => {
const fetchSession = async () => { const fetchSession = async () => {
try { try {
const { data } = await api.get('/settings') const { data } = await api.get('/settings')
setSettings(data) setSettings(data.settings)
} catch (err) { } catch (err) {
toastError(err) toastError(err)
} }
@ -205,6 +210,13 @@ const Connections = () => {
setWhatsAppModalOpen(true) setWhatsAppModalOpen(true)
} }
const handleOpenConfigModal = () => {
setConfigModalOpen(true)
}
const handleCloseConfigModal = () => {
setConfigModalOpen(false)
}
const handleCloseWhatsAppModal = useCallback(() => { const handleCloseWhatsAppModal = useCallback(() => {
setWhatsAppModalOpen(false) setWhatsAppModalOpen(false)
setSelectedWhatsApp(null) setSelectedWhatsApp(null)
@ -454,10 +466,24 @@ const Connections = () => {
whatsAppId={!qrModalOpen && selectedWhatsApp?.id} whatsAppId={!qrModalOpen && selectedWhatsApp?.id}
/> />
<ConfigModal
open={configModalOpen}
onClose={handleCloseConfigModal}
change={configModalOpen}
/>
<MainHeader> <MainHeader>
<Title>{i18n.t('connections.title')}</Title> <Title>{i18n.t('connections.title')}</Title>
<MainHeaderButtonsWrapper> <MainHeaderButtonsWrapper>
<Button
variant="contained"
color="primary"
onClick={handleOpenConfigModal}
>
<Settings/>
</Button>
<Can <Can
role={user.profile} role={user.profile}
perform="btn-add-whatsapp" perform="btn-add-whatsapp"

View File

@ -121,7 +121,7 @@ const Queues = () => {
const fetchSession = async () => { const fetchSession = async () => {
try { try {
const { data } = await api.get('/settings') const { data } = await api.get('/settings')
setSettings(data) setSettings(data.settings)
} catch (err) { } catch (err) {
toastError(err) toastError(err)
} }

View File

@ -52,7 +52,7 @@ const Settings = () => {
const fetchSession = async () => { const fetchSession = async () => {
try { try {
const { data } = await api.get('/settings') const { data } = await api.get('/settings')
setSettings(data) setSettings(data.settings)
} catch (err) { } catch (err) {
toastError(err) toastError(err)
} }