Adicionar arquivos de projeto.

This commit is contained in:
Leandro Palmeira 2025-03-17 11:58:43 -03:00
parent 5420f291db
commit 83fc86113a
946 changed files with 121901 additions and 0 deletions

9
backend/.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
end_of_line = lf
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

35
backend/.env.example Normal file
View File

@ -0,0 +1,35 @@
NODE_ENV=
BACKEND_URL=http://localhost
FRONTEND_URL=http://localhost:3000
PROXY_PORT=8080
PORT=8080
DB_DIALECT=postgres
DB_HOST=localhost
DB_PORT=5432
DB_USER=user
DB_PASS=senha
DB_NAME=db_name
JWT_SECRET=kZaOTd+YZpjRUyyuQUpigJaEMk4vcW4YOymKPZX0Ts8=
JWT_REFRESH_SECRET=dBSXqFg9TaNUEDXVp6fhMTRLBysP+j2DSqf7+raxD3A=
REDIS_URI=redis://:123456@127.0.0.1:6379
REDIS_OPT_LIMITER_MAX=1
REDIS_OPT_LIMITER_DURATION=3000
USER_LIMIT=10000
CONNECTIONS_LIMIT=100000
CLOSED_SEND_BY_ME=true
GERENCIANET_SANDBOX=false
GERENCIANET_CLIENT_ID=Client_Id_Gerencianet
GERENCIANET_CLIENT_SECRET=Client_Secret_Gerencianet
GERENCIANET_PIX_CERT=certificado-Gerencianet
GERENCIANET_PIX_KEY=chave pix gerencianet
MAIL_HOST="smtp.hostinger.com"
MAIL_USER="contato@seusite.com"
MAIL_PASS="senha"
MAIL_FROM="Recuperar Senha <contato@seusite.com>"
MAIL_PORT="465"

3
backend/.eslintignore Normal file
View File

@ -0,0 +1,3 @@
/*.js
node_modules
dist

49
backend/.eslintrc.json Normal file
View File

@ -0,0 +1,49 @@
{
"env": {
"es2021": true,
"node": true,
"jest": true
},
"extends": [
"airbnb-base",
"plugin:@typescript-eslint/recommended",
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{ "argsIgnorePattern": "_" }
],
"import/prefer-default-export": "off",
"no-console": "off",
"no-param-reassign": "off",
"prettier/prettier": "error",
"import/extensions": [
"error",
"ignorePackages",
{
"ts": "never"
}
],
"quotes": [
1,
"double",
{
"avoidEscape": true
}
]
},
"settings": {
"import/resolver": {
"typescript": {}
}
}
}

13
backend/.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
node_modules
public/*
!public/logotipos/
!public/.gitkeep
dist
.env
.env.test
package-lock.json
yarn.lock
yarn-error.log
/src/config/sentry.js
coverage.data
coverage/

8
backend/.sequelizerc Normal file
View File

@ -0,0 +1,8 @@
const { resolve } = require("path");
module.exports = {
"config": resolve(__dirname, "dist", "config", "database.js"),
"modules-path": resolve(__dirname, "dist", "models"),
"migrations-path": resolve(__dirname, "dist", "database", "migrations"),
"seeders-path": resolve(__dirname, "dist", "database", "seeds")
};

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,9 @@
module.exports = [{
script: 'dist/server.js',
name: 'beta-back',
exec_mode: 'fork',
cron_restart: '05 00 * * *',
max_memory_restart: '769M', // Configuração para reiniciar quando atingir 769 MB de memória
node_args: '--max-old-space-size=769', // Limite de memória do Node.js para 769 MB
watch: false
}]

186
backend/jest.config.js Normal file
View File

@ -0,0 +1,186 @@
/*
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/en/configuration.html
*/
module.exports = {
// All imported modules in your tests should be mocked automatically
// automock: false,
// Stop running tests after `n` failures
bail: 1,
// The directory where Jest should store its cached dependency information
// cacheDirectory: "/tmp/jest_rs",
// Automatically clear mock calls and instances between every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
collectCoverage: true,
// An array of glob patterns indicating a set of files for which coverage information should be collected
collectCoverageFrom: ["<rootDir>/src/services/**/*.ts"],
// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
// Indicates which provider should be used to instrument code for coverage
coverageProvider: "v8",
// A list of reporter names that Jest uses when writing coverage reports
coverageReporters: ["text", "lcov"],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,
// A path to a custom dependency extractor
// dependencyExtractor: undefined,
// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,
// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],
// A path to a module which exports an async function that is triggered once before all test suites
// globalSetup: undefined,
// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
// A set of global variables that need to be available in all test environments
// globals: {},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",
// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],
// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "json",
// "jsx",
// "ts",
// "tsx",
// "node"
// ],
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
// moduleNameMapper: {},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
// Activates notifications for test results
// notify: false,
// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",
// A preset that is used as a base for Jest's configuration
preset: "ts-jest",
// Run tests from one or more projects
// projects: undefined,
// Use this configuration option to add custom reporters to Jest
// reporters: undefined,
// Automatically reset mock state between every test
// resetMocks: false,
// Reset the module registry before running each individual test
// resetModules: false,
// A path to a custom resolver
// resolver: undefined,
// Automatically restore mock state between every test
// restoreMocks: false,
// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,
// A list of paths to directories that Jest should use to search for files in
// roots: [
// "<rootDir>"
// ],
// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
// The test environment that will be used for testing
testEnvironment: "node",
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
testMatch: ["**/__tests__/**/*.spec.ts"]
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
// This option allows the use of a custom results processor
// testResultsProcessor: undefined,
// This option allows use of a custom test runner
// testRunner: "jasmine2",
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
// testURL: "http://localhost",
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
// timers: "real",
// A map from regular expressions to paths to transformers
// transform: undefined,
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/",
// "\\.pnp\\.[^\\/]+$"
// ],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
// Indicates whether each individual test should be reported during the run
// verbose: undefined,
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],
// Whether to use watchman for file crawling
// watchman: true,
};

113
backend/package.json Normal file
View File

@ -0,0 +1,113 @@
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc --sourceMap false",
"devbuild": "tsc --sourceMap true",
"watch": "tsc -w",
"start": "node --max-old-space-size=8096 dist/server.js",
"dev": "tsc-watch --onSuccess \"node --max-old-space-size=8096 --trace-warnings ./dist/server.js\"",
"dev:server": "node --max-old-space-size=8096 -r ts-node/register src/server.ts",
"db:migrate": "npx sequelize db:migrate",
"db:seed": "sequelize db:seed:all",
"pretest": "NODE_ENV=test sequelize db:migrate && NODE_ENV=test sequelize db:seed:all",
"test": "NODE_ENV=test jest",
"posttest": "NODE_ENV=test sequelize db:migrate:undo:all",
"lint": "eslint src/**/*.ts"
},
"author": "",
"license": "MIT",
"dependencies": {
"@adiwajshing/keyed-db": "^0.2.4",
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@hapi/boom": "^9.1.4",
"@sentry/node": "^6.18.1",
"@types/fs-extra": "^11.0.4",
"@whiskeysockets/baileys": "^6.7.9",
"async-mutex": "^0.4.1",
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.2",
"bull": "^4.8.2",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"cron": "^2.1.0",
"date-fns": "^2.28.0",
"dotenv": "^16.0.0",
"express": "^4.17.3",
"express-async-errors": "^3.1.1",
"ffmpeg-static": "^5.2.0",
"fluent-ffmpeg": "^2.1.3",
"gn-api-sdk-typescript": "^1.0.7",
"http-graceful-shutdown": "^3.1.6",
"image-size": "^1.2.0",
"ioredis": "^5.4.1",
"jsonwebtoken": "^8.5.1",
"microsoft-cognitiveservices-speech-sdk": "1.31.0",
"multer": "^1.4.4",
"mustache": "^4.2.0",
"mysql2": "^2.2.5",
"node-cache": "^5.1.2",
"node-cron": "^3.0.2",
"nodemailer": "^6.8.0",
"notificamehubsdk": "^0.0.19",
"openai": "3.3.0",
"pg": "^8.7.3",
"pino": "^7.8.0",
"pino-pretty": "^10.0.0",
"puppeteer": "^19.4.0",
"qrcode-terminal": "^0.12.0",
"reflect-metadata": "^0.1.13",
"request": "2.88.2",
"sequelize": "^5.22.3",
"sequelize-cli": "^5.5.1",
"sequelize-typescript": "^1.1.0",
"socket.io": "^4.7.4",
"uuid": "^8.3.2",
"xlsx": "^0.18.3",
"yup": "^0.32.11"
},
"devDependencies": {
"@types/bcryptjs": "^2.4.2",
"@types/bluebird": "^3.5.36",
"@types/chance": "^1.1.3",
"@types/cookie-parser": "^1.4.2",
"@types/cors": "^2.8.12",
"@types/express": "^4.17.13",
"@types/factory-girl": "^5.0.8",
"@types/faker": "^5.1.3",
"@types/fluent-ffmpeg": "^2.1.26",
"@types/fs-extra": "^11.0.4",
"@types/image-size": "^0.7.0",
"@types/ioredis": "^5.0.0",
"@types/jest": "^27.4.1",
"@types/jsonwebtoken": "^8.5.0",
"@types/multer": "^1.4.7",
"@types/mustache": "^4.1.2",
"@types/node": "^14.11.8",
"@types/pino-pretty": "~4.7.1",
"@types/supertest": "^2.0.11",
"@types/uuid": "^8.3.4",
"@types/validator": "^13.1.0",
"@types/yup": "^0.29.13",
"@typescript-eslint/eslint-plugin": "^5.13.0",
"@typescript-eslint/parser": "^5.13.0",
"chance": "^1.1.8",
"eslint": "^8.10.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^2.5.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-prettier": "^4.0.0",
"factory-girl": "^5.0.4",
"faker": "^5.1.0",
"jest": "^27.5.1",
"nodemon": "^2.0.15",
"prettier": "^2.5.1",
"supertest": "^6.2.2",
"ts-jest": "^27.1.3",
"ts-node-dev": "^1.1.8",
"typescript": "^4.6.3"
}
}

View File

@ -0,0 +1,5 @@
module.exports = {
singleQuote: false,
trailingComma: "none",
arrowParens: "avoid"
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

5
backend/src/@types/express.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare namespace Express {
export interface Request {
user: { id: string; profile: string; companyId: number };
}
}

View File

@ -0,0 +1 @@
declare module "qrcode-terminal";

53
backend/src/app.ts Normal file
View File

@ -0,0 +1,53 @@
import * as Sentry from "@sentry/node";
import cookieParser from "cookie-parser";
import cors from "cors";
import express, { NextFunction, Request, Response } from "express";
import "express-async-errors";
import "reflect-metadata";
import "./bootstrap";
import bodyParser from 'body-parser';
import uploadConfig from "./config/upload";
import "./database";
import AppError from "./errors/AppError";
import { messageQueue, sendScheduledMessages } from "./queues";
import routes from "./routes";
import { logger } from "./utils/logger";
Sentry.init({ dsn: process.env.SENTRY_DSN });
const app = express();
app.set("queues", {
messageQueue,
sendScheduledMessages
});
const bodyparser = require('body-parser');
app.use(bodyParser.json({ limit: '10mb' }));
app.use(
cors({
credentials: true,
origin: process.env.FRONTEND_URL
})
);
app.use(cookieParser());
app.use(express.json());
app.use(Sentry.Handlers.requestHandler());
app.use("/public", express.static(uploadConfig.directory));
app.use(routes);
app.use(Sentry.Handlers.errorHandler());
app.use(async (err: Error, req: Request, res: Response, _: NextFunction) => {
if (err instanceof AppError) {
logger.warn(err);
return res.status(err.statusCode).json({ error: err.message });
}
logger.error(err);
return res.status(500).json({ error: "Internal server error" });
});
export default app;

5
backend/src/bootstrap.ts Normal file
View File

@ -0,0 +1,5 @@
import dotenv from "dotenv";
dotenv.config({
path: process.env.NODE_ENV === "test" ? ".env.test" : ".env"
});

13
backend/src/config/Gn.ts Normal file
View File

@ -0,0 +1,13 @@
import path from "path";
const cert = path.join(
__dirname,
`../../certs/${process.env.GERENCIANET_PIX_CERT}.p12`
);
export = {
sandbox: false,
client_id: process.env.GERENCIANET_CLIENT_ID as string,
client_secret: process.env.GERENCIANET_CLIENT_SECRET as string,
pix_cert: cert
};

View File

@ -0,0 +1,6 @@
export default {
secret: process.env.JWT_SECRET || "mysecret",
expiresIn: "15m",
refreshSecret: process.env.JWT_REFRESH_SECRET || "myanothersecret",
refreshExpiresIn: "7d"
};

View File

@ -0,0 +1,16 @@
import "../bootstrap";
module.exports = {
define: {
charset: "utf8mb4",
collate: "utf8mb4_bin"
},
dialect: process.env.DB_DIALECT || "mysql",
timezone: "-03:00",
host: process.env.DB_HOST,
port: process.env.DB_PORT || 3306,
database: process.env.DB_NAME,
username: process.env.DB_USER,
password: process.env.DB_PASS,
logging: process.env.DB_DEBUG === "true"
};

View File

@ -0,0 +1,3 @@
export const REDIS_URI_CONNECTION = process.env.REDIS_URI || "";
export const REDIS_OPT_LIMITER_MAX = process.env.REDIS_OPT_LIMITER_MAX || 1;
export const REDIS_OPT_LIMITER_DURATION = process.env.REDIS_OPT_LIMITER_DURATION || 3000;

View File

@ -0,0 +1,50 @@
import path from "path";
import multer from "multer";
import fs from "fs";
import Whatsapp from "../models/Whatsapp";
import { isEmpty, isNil } from "lodash";
const publicFolder = path.resolve(__dirname, "..", "..", "public");
export default {
directory: publicFolder,
storage: multer.diskStorage({
destination: async function (req, file, cb) {
let companyId;
companyId = req.user?.companyId
const { typeArch, fileId } = req.body;
if (companyId === undefined && isNil(companyId) && isEmpty(companyId)) {
const authHeader = req.headers.authorization;
const [, token] = authHeader.split(" ");
const whatsapp = await Whatsapp.findOne({ where: { token } });
companyId = whatsapp.companyId;
}
let folder;
if (typeArch && typeArch !== "announcements" && typeArch !== "logo") {
folder = path.resolve(publicFolder, `company${companyId}`, typeArch, fileId ? fileId : "")
} else if (typeArch && typeArch === "announcements") {
folder = path.resolve(publicFolder, typeArch)
} else if (typeArch === "logo") {
folder = path.resolve(publicFolder)
}
else {
folder = path.resolve(publicFolder, `company${companyId}`)
}
if (!fs.existsSync(folder)) {
fs.mkdirSync(folder, { recursive: true })
fs.chmodSync(folder, 0o777)
}
return cb(null, folder);
},
filename(req, file, cb) {
const { typeArch } = req.body;
const fileName = typeArch && typeArch !== "announcements" ? file.originalname.replace('/', '-').replace(/ /g, "_") : new Date().getTime() + '_' + file.originalname.replace('/', '-').replace(/ /g, "_");
return cb(null, fileName);
}
})
};

View File

@ -0,0 +1,19 @@
import path from "path";
import multer from "multer";
const publicFolder = path.resolve(__dirname, "..", "..", "public/logotipos");
export default {
directory: publicFolder,
storage: multer.diskStorage({
destination: publicFolder,
filename(req, file, cb) {
const desiredFileName = req.query.ref + path.extname(file.originalname);
return cb(null, desiredFileName);
}
})
};

View File

@ -0,0 +1,47 @@
import path from "path";
import multer from "multer";
import fs from "fs";
import Whatsapp from "../models/Whatsapp";
import { isEmpty, isNil } from "lodash";
const publicFolder = path.resolve(__dirname, "..", "..", "public");
export default {
directory: publicFolder,
storage: multer.diskStorage({
destination: async function (req, file, cb) {
let companyId;
if (req.user?.companyId) {
companyId = req.user.companyId;
} else {
const authHeader = req.headers.authorization;
const [, token] = authHeader.split(" ");
const whatsapp = await Whatsapp.findOne({ where: { token } });
companyId = whatsapp.companyId;
}
const companyFolder = `${publicFolder}/company${companyId}`;
// Criar a pasta company{companyId} caso ela não exista
if (!fs.existsSync(companyFolder)) {
fs.mkdirSync(companyFolder, { recursive: true });
fs.chmodSync(companyFolder, 0o777);
}
const folder = `${companyFolder}/quick/`;
// Criar a pasta quick/ caso ela não exista
if (!fs.existsSync(folder)) {
fs.mkdirSync(folder, { recursive: true });
fs.chmodSync(folder, 0o777);
}
return cb(null, folder);
},
filename(req, file, cb) {
const fileName = `${new Date().getTime()}_${file.originalname.replace("/", "-")}`;
return cb(null, fileName);
}
})
};

View File

@ -0,0 +1,205 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import { head } from "lodash";
import fs from "fs";
import path from "path";
import ListService from "../services/AnnouncementService/ListService";
import CreateService from "../services/AnnouncementService/CreateService";
import ShowService from "../services/AnnouncementService/ShowService";
import UpdateService from "../services/AnnouncementService/UpdateService";
import DeleteService from "../services/AnnouncementService/DeleteService";
import FindService from "../services/AnnouncementService/FindService";
import Announcement from "../models/Announcement";
import AppError from "../errors/AppError";
type IndexQuery = {
searchParam: string;
pageNumber: string;
companyId: string | number;
};
type StoreData = {
priority: string;
title: string;
text: string;
status: string;
companyId: number;
mediaPath?: string;
mediaName?: string;
};
type FindParams = {
companyId: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { records, count, hasMore } = await ListService({
searchParam,
pageNumber
});
return res.json({ records, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const data = req.body as StoreData;
const schema = Yup.object().shape({
title: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const record = await CreateService({
...data,
companyId
});
const io = getIO();
io.emit(`company-announcement`, {
action: "create",
record
});
return res.status(200).json(record);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const record = await ShowService(id);
return res.status(200).json(record);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const data = req.body as StoreData;
const schema = Yup.object().shape({
title: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const { id } = req.params;
const record = await UpdateService({
...data,
id
});
const io = getIO();
io.emit(`company-announcement`, {
action: "update",
record
});
return res.status(200).json(record);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user;
await DeleteService(id);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-announcement`, {
action: "delete",
id
});
return res.status(200).json({ message: "Announcement deleted" });
};
export const findList = async (
req: Request,
res: Response
): Promise<Response> => {
const params = req.query as FindParams;
const records: Announcement[] = await FindService(params);
return res.status(200).json(records);
};
export const mediaUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const files = req.files as Express.Multer.File[];
const file = head(files);
try {
const announcement = await Announcement.findByPk(id);
await announcement.update({
mediaPath: file.filename,
mediaName: file.originalname
});
await announcement.reload();
const io = getIO();
io.emit(`company-announcement`, {
action: "update",
record: announcement
});
return res.send({ mensagem: "Mensagem enviada" });
} catch (err: any) {
throw new AppError(err.message);
}
};
export const deleteMedia = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
try {
const announcement = await Announcement.findByPk(id);
const filePath = path.resolve("public", announcement.mediaPath);
const fileExists = fs.existsSync(filePath);
if (fileExists) {
fs.unlinkSync(filePath);
}
await announcement.update({
mediaPath: null,
mediaName: null
});
await announcement.reload();
const io = getIO();
io.emit(`company-announcement`, {
action: "update",
record: announcement
});
return res.send({ mensagem: "Arquivo excluído" });
} catch (err: any) {
throw new AppError(err.message);
}
};

View File

@ -0,0 +1,205 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import { head } from "lodash";
import fs from "fs";
import path from "path";
import ListService from "../services/AnnouncementService/ListService";
import CreateService from "../services/AnnouncementService/CreateService";
import ShowService from "../services/AnnouncementService/ShowService";
import UpdateService from "../services/AnnouncementService/UpdateService";
import DeleteService from "../services/AnnouncementService/DeleteService";
import FindService from "../services/AnnouncementService/FindService";
import Announcement from "../models/Announcement";
import AppError from "../errors/AppError";
type IndexQuery = {
searchParam: string;
pageNumber: string;
companyId: string | number;
};
type StoreData = {
priority: string;
title: string;
text: string;
status: string;
companyId: number;
mediaPath?: string;
mediaName?: string;
};
type FindParams = {
companyId: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { records, count, hasMore } = await ListService({
searchParam,
pageNumber
});
return res.json({ records, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const data = req.body as StoreData;
const schema = Yup.object().shape({
title: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const record = await CreateService({
...data,
companyId
});
const io = getIO();
io.emit(`company-announcement`, {
action: "create",
record
});
return res.status(200).json(record);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const record = await ShowService(id);
return res.status(200).json(record);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const data = req.body as StoreData;
const schema = Yup.object().shape({
title: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const { id } = req.params;
const record = await UpdateService({
...data,
id
});
const io = getIO();
io.emit(`company-announcement`, {
action: "update",
record
});
return res.status(200).json(record);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user;
await DeleteService(id);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-announcement`, {
action: "delete",
id
});
return res.status(200).json({ message: "Announcement deleted" });
};
export const findList = async (
req: Request,
res: Response
): Promise<Response> => {
const params = req.query as FindParams;
const records: Announcement[] = await FindService(params);
return res.status(200).json(records);
};
export const mediaUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const files = req.files as Express.Multer.File[];
const file = head(files);
try {
const announcement = await Announcement.findByPk(id);
await announcement.update({
mediaPath: file.filename,
mediaName: file.originalname
});
await announcement.reload();
const io = getIO();
io.emit(`company-announcement`, {
action: "update",
record: announcement
});
return res.send({ mensagem: "Mensagem enviada" });
} catch (err: any) {
throw new AppError(err.message);
}
};
export const deleteMedia = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
try {
const announcement = await Announcement.findByPk(id);
const filePath = path.resolve("public", announcement.mediaPath);
const fileExists = fs.existsSync(filePath);
if (fileExists) {
fs.unlinkSync(filePath);
}
await announcement.update({
mediaPath: null,
mediaName: null
});
await announcement.reload();
const io = getIO();
io.emit(`company-announcement`, {
action: "update",
record: announcement
});
return res.send({ mensagem: "Arquivo excluído" });
} catch (err: any) {
throw new AppError(err.message);
}
};

View File

@ -0,0 +1,289 @@
import { Request, Response } from "express";
import fs from "fs";
import { head } from "lodash";
import path from "path";
import * as Yup from "yup";
import { getIO } from "../libs/socket";
import CreateService from "../services/CampaignService/CreateService";
import DeleteService from "../services/CampaignService/DeleteService";
import FindService from "../services/CampaignService/FindService";
import ListService from "../services/CampaignService/ListService";
import ShowService from "../services/CampaignService/ShowService";
import UpdateService from "../services/CampaignService/UpdateService";
import Campaign from "../models/Campaign";
import AppError from "../errors/AppError";
import Contact from "../models/Contact";
import ContactList from "../models/ContactList";
import ContactListItem from "../models/ContactListItem";
import Ticket from "../models/Ticket";
import TicketTag from "../models/TicketTag";
import { CancelService } from "../services/CampaignService/CancelService";
import { RestartService } from "../services/CampaignService/RestartService";
type IndexQuery = {
searchParam: string;
pageNumber: string;
companyId: string | number;
};
type StoreData = {
name: string;
status: string;
confirmation: boolean;
scheduledAt: string;
companyId: number;
contactListId: number;
tagListId: number | string;
fileListId: number;
};
type FindParams = {
companyId: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { companyId } = req.user;
const { records, count, hasMore } = await ListService({
searchParam,
pageNumber,
companyId
});
return res.json({ records, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const data = req.body as StoreData;
console.log('data------- store:', data);
const schema = Yup.object().shape({
name: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
if (typeof data.tagListId === 'number') {
const tagId = data.tagListId;
const campanhaNome = data.name;
async function createContactListFromTag(tagId) {
const currentDate = new Date();
const formattedDate = currentDate.toISOString();
try {
const ticketTags = await TicketTag.findAll({ where: { tagId } });
const ticketIds = ticketTags.map((ticketTag) => ticketTag.ticketId);
const tickets = await Ticket.findAll({ where: { id: ticketIds } });
const contactIds = tickets.map((ticket) => ticket.contactId);
const contacts = await Contact.findAll({ where: { id: contactIds } });
const randomName = `${campanhaNome} | TAG: ${tagId} - ${formattedDate}` // Implement your own function to generate a random name
const contactList = await ContactList.create({ name: randomName, companyId: companyId });
const { id: contactListId } = contactList;
const contactListItems = contacts.map((contact) => ({
name: contact.name,
number: contact.number,
email: contact.email,
contactListId,
companyId,
isWhatsappValid: true,
}));
await ContactListItem.bulkCreate(contactListItems);
// Return the ContactList ID
return contactListId;
} catch (error) {
console.error('Error creating contact list:', error);
throw error;
}
}
createContactListFromTag(tagId)
.then(async (contactListId) => {
const record = await CreateService({
...data,
companyId,
contactListId: contactListId,
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-campaign`, {
action: "create",
record
});
return res.status(200).json(record);
})
.catch((error) => {
console.error('Error:', error);
return res.status(500).json({ error: 'Error creating contact list' });
});
} else { // SAI DO CHECK DE TAG
const record = await CreateService({
...data,
companyId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-campaign`, {
action: "create",
record
});
return res.status(200).json(record);
}
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const record = await ShowService(id);
return res.status(200).json(record);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const data = req.body as StoreData;
const { companyId } = req.user;
const schema = Yup.object().shape({
name: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const { id } = req.params;
const record = await UpdateService({
...data,
id
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-campaign`, {
action: "update",
record
});
return res.status(200).json(record);
};
export const cancel = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
await CancelService(+id);
return res.status(204).json({ message: "Cancelamento realizado" });
};
export const restart = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
await RestartService(+id);
return res.status(204).json({ message: "Reinício dos disparos" });
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user;
await DeleteService(id);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-campaign`, {
action: "delete",
id
});
return res.status(200).json({ message: "Campaign deleted" });
};
export const findList = async (
req: Request,
res: Response
): Promise<Response> => {
const params = req.query as FindParams;
const records: Campaign[] = await FindService(params);
return res.status(200).json(records);
};
export const mediaUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const files = req.files as Express.Multer.File[];
const file = head(files);
try {
const campaign = await Campaign.findByPk(id);
campaign.mediaPath = file.filename;
campaign.mediaName = file.originalname;
await campaign.save();
return res.send({ mensagem: "Mensagem enviada" });
} catch (err: any) {
throw new AppError(err.message);
}
};
export const deleteMedia = async (
req: Request,
res: Response
): Promise<Response> => {
const { companyId } = req.user;
const { id } = req.params;
try {
const campaign = await Campaign.findByPk(id);
const filePath = path.resolve("public", `company${companyId}`, campaign.mediaPath);
const fileExists = fs.existsSync(filePath);
if (fileExists) {
fs.unlinkSync(filePath);
}
campaign.mediaPath = null;
campaign.mediaName = null;
await campaign.save();
return res.send({ mensagem: "Arquivo excluído" });
} catch (err: any) {
throw new AppError(err.message);
}
};

View File

@ -0,0 +1,34 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import ListService from "../services/CampaignSettingServices/ListService";
import CreateService from "../services/CampaignSettingServices/CreateService";
interface StoreData {
settings: any;
}
export const index = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const records = await ListService({
companyId
});
return res.json(records);
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const data = req.body as StoreData;
const record = await CreateService(data, companyId);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-campaignSettings`, {
action: "create",
record
});
return res.status(200).json(record);
};

View File

@ -0,0 +1,38 @@
import { Request, Response } from "express";
import CreateChannelsService from "../services/HubServices/CreateHubChannelsService";
import { setChannelWebhook } from "../helpers/setChannelHubWebhook";
import { getIO } from "../libs/socket";
import ListChannels from "../services/HubServices/ListHubChannels";
export interface IChannel {
name: string;
status?: string;
isDefault?: boolean;
qrcode?: string;
type?: string;
channel?: string;
id?:string;
}
export const store = async (req: Request, res: Response): Promise<Response> => {
const { whatsapps } = await CreateChannelsService(req.body);
whatsapps.forEach(whatsapp => {
setTimeout(() => {
setChannelWebhook(whatsapp, whatsapp.id.toString());
}, 2000);
});
return res.status(200).json(whatsapps);
};
export const index = async (req: Request, res: Response): Promise<Response> => {
try {
const channels = await ListChannels();
return res.status(200).json(channels);
} catch (error) {
return res.status(500).json({ error: error });
}
};

View File

@ -0,0 +1,205 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import CreateService from "../services/ChatService/CreateService";
import ListService from "../services/ChatService/ListService";
import ShowFromUuidService from "../services/ChatService/ShowFromUuidService";
import DeleteService from "../services/ChatService/DeleteService";
import FindMessages from "../services/ChatService/FindMessages";
import UpdateService from "../services/ChatService/UpdateService";
import Chat from "../models/Chat";
import CreateMessageService from "../services/ChatService/CreateMessageService";
import User from "../models/User";
import ChatUser from "../models/ChatUser";
type IndexQuery = {
pageNumber: string;
companyId: string | number;
ownerId?: number;
};
type StoreData = {
users: any[];
title: string;
};
type FindParams = {
companyId: number;
ownerId?: number;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { pageNumber } = req.query as unknown as IndexQuery;
const ownerId = +req.user.id;
const { records, count, hasMore } = await ListService({
ownerId,
pageNumber
});
return res.json({ records, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const ownerId = +req.user.id;
const data = req.body as StoreData;
const record = await CreateService({
...data,
ownerId,
companyId
});
const io = getIO();
record.users.forEach(user => {
io.to(`user-${user.userId}`).emit(`company-${companyId}-chat-user-${user.userId}`, {
action: "create",
record
});
});
return res.status(200).json(record);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const { companyId } = req.user;
const data = req.body;
const { id } = req.params;
const record = await UpdateService({
...data,
id: +id
});
const io = getIO();
record.users.forEach(user => {
io.to(`user-${user.userId}`).emit(`company-${companyId}-chat-user-${user.userId}`, {
action: "update",
record
});
});
return res.status(200).json(record);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const record = await ShowFromUuidService(id);
return res.status(200).json(record);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user;
await DeleteService(id);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-chat`, {
action: "delete",
id
});
return res.status(200).json({ message: "Chat deleted" });
};
export const saveMessage = async (
req: Request,
res: Response
): Promise<Response> => {
const { companyId } = req.user;
const { message } = req.body;
const { id } = req.params;
const senderId = +req.user.id;
const chatId = +id;
const newMessage = await CreateMessageService({
chatId,
senderId,
message
});
const chat = await Chat.findByPk(chatId, {
include: [
{ model: User, as: "owner" },
{ model: ChatUser, as: "users" }
]
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-chat-${chatId}`, {
action: "new-message",
newMessage,
chat
});
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-chat`, {
action: "new-message",
newMessage,
chat
});
return res.json(newMessage);
};
export const checkAsRead = async (
req: Request,
res: Response
): Promise<Response> => {
const { companyId } = req.user;
const { userId } = req.body;
const { id } = req.params;
const chatUser = await ChatUser.findOne({ where: { chatId: id, userId } });
await chatUser.update({ unreads: 0 });
const chat = await Chat.findByPk(id, {
include: [
{ model: User, as: "owner" },
{ model: ChatUser, as: "users" }
]
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-chat-${id}`, {
action: "update",
chat
});
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-chat`, {
action: "update",
chat
});
return res.json(chat);
};
export const messages = async (
req: Request,
res: Response
): Promise<Response> => {
const { pageNumber } = req.query as unknown as IndexQuery;
const { id: chatId } = req.params;
const ownerId = +req.user.id;
const { records, count, hasMore } = await FindMessages({
chatId,
ownerId,
pageNumber
});
return res.json({ records, count, hasMore });
};

View File

@ -0,0 +1,200 @@
import { Request, Response } from "express";
import * as Yup from "yup";
// import { getIO } from "../libs/socket";
import authConfig from "../config/auth";
import AppError from "../errors/AppError";
import Company from "../models/Company";
import fs from "fs";
import path from "path";
import { verify } from "jsonwebtoken";
import User from "../models/User";
import CreateCompanyService from "../services/CompanyService/CreateCompanyService";
import DeleteCompanyService from "../services/CompanyService/DeleteCompanyService";
import FindAllCompaniesService from "../services/CompanyService/FindAllCompaniesService";
import ListCompaniesPlanService from "../services/CompanyService/ListCompaniesPlanService";
import ListCompaniesService from "../services/CompanyService/ListCompaniesService";
import ShowCompanyService from "../services/CompanyService/ShowCompanyService";
import ShowPlanCompanyService from "../services/CompanyService/ShowPlanCompanyService";
import UpdateCompanyService from "../services/CompanyService/UpdateCompanyService";
import UpdateSchedulesService from "../services/CompanyService/UpdateSchedulesService";
const publicFolder = path.resolve(__dirname, "..", "..", "public");
type IndexQuery = {
searchParam: string;
pageNumber: string;
};
interface TokenPayload {
id: string;
username: string;
profile: string;
companyId: number;
iat: number;
exp: number;
}
type CompanyData = {
name: string;
id?: number;
phone?: string;
email?: string;
status?: boolean;
planId?: number;
campaignsEnabled?: boolean;
dueDate?: string;
recurrence?: string;
};
type SchedulesData = {
schedules: [];
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { companies, count, hasMore } = await ListCompaniesService({
searchParam,
pageNumber
});
return res.json({ companies, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const newCompany: CompanyData = req.body;
const schema = Yup.object().shape({
name: Yup.string().required()
});
try {
await schema.validate(newCompany);
} catch (err: any) {
throw new AppError(err.message);
}
const company = await CreateCompanyService(newCompany);
return res.status(200).json(company);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const company = await ShowCompanyService(id);
return res.status(200).json(company);
};
export const list = async (req: Request, res: Response): Promise<Response> => {
const companies: Company[] = await FindAllCompaniesService();
return res.status(200).json(companies);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const companyData: CompanyData = req.body;
const schema = Yup.object().shape({
name: Yup.string()
});
try {
await schema.validate(companyData);
} catch (err: any) {
throw new AppError(err.message);
}
const { id } = req.params;
const company = await UpdateCompanyService({ id, ...companyData });
return res.status(200).json(company);
};
export const updateSchedules = async (
req: Request,
res: Response
): Promise<Response> => {
const { schedules }: SchedulesData = req.body;
const { id } = req.params;
const company = await UpdateSchedulesService({
id,
schedules
});
return res.status(200).json(company);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const userId = req.user.id;
const requestUser = await User.findByPk(userId);
if (requestUser.super === false) {
throw new AppError("você nao tem permissão para este consulta");
}
const { id } = req.params;
if (fs.existsSync(`${publicFolder}/company${id}/`)) {
const removefolder = await fs.rmdirSync(`${publicFolder}/company${id}/`, {
recursive: true,
});
}
const company = await DeleteCompanyService(id);
//fs.remove(`${publicFolder}/company${id}/`);
return res.status(200).json(company);
};
export const listPlan = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const authHeader = req.headers.authorization;
const [, token] = authHeader.split(" ");
const decoded = verify(token, authConfig.secret);
const { id: requestUserId, profile, companyId } = decoded as TokenPayload;
const requestUser = await User.findByPk(requestUserId);
if (requestUser.super === true) {
const company = await ShowPlanCompanyService(id);
return res.status(200).json(company);
} else if (companyId.toString() !== id) {
return res.status(400).json({ error: "Você não possui permissão para acessar este recurso!" });
} else {
const company = await ShowPlanCompanyService(id);
return res.status(200).json(company);
}
};
export const indexPlan = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const authHeader = req.headers.authorization;
const [, token] = authHeader.split(" ");
const decoded = verify(token, authConfig.secret);
const { id, profile, companyId } = decoded as TokenPayload;
// const company = await Company.findByPk(companyId);
const requestUser = await User.findByPk(id);
if (requestUser.super === true) {
const companies = await ListCompaniesPlanService();
return res.json({ companies });
} else {
return res.status(400).json({ error: "Você não possui permissão para acessar este recurso!" });
}
};

View File

@ -0,0 +1,259 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import Contact from "../models/Contact";
import ListContactsService from "../services/ContactServices/ListContactsService";
import CreateContactService from "../services/ContactServices/CreateContactService";
import ShowContactService from "../services/ContactServices/ShowContactService";
import UpdateContactService from "../services/ContactServices/UpdateContactService";
import DeleteContactService from "../services/ContactServices/DeleteContactService";
import GetContactService from "../services/ContactServices/GetContactService";
import CheckContactNumber from "../services/WbotServices/CheckNumber";
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
import AppError from "../errors/AppError";
import SimpleListService, {
SearchContactParams
} from "../services/ContactServices/SimpleListService";
import ContactCustomField from "../models/ContactCustomField";
import {head} from "lodash";
import {ImportContacts} from "../services/ContactServices/ImportContacts";
type IndexQuery = {
searchParam: string;
pageNumber: string;
};
type IndexGetContactQuery = {
name: string;
number: string;
};
interface ExtraInfo extends ContactCustomField {
name: string;
value: string;
}
interface ContactData {
name: string;
number: string;
email?: string;
extraInfo?: ExtraInfo[];
}
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { companyId } = req.user;
const { contacts, count, hasMore } = await ListContactsService({
searchParam,
pageNumber,
companyId
});
return res.json({ contacts, count, hasMore });
};
export const getContact = async (
req: Request,
res: Response
): Promise<Response> => {
const { name, number } = req.body as IndexGetContactQuery;
const { companyId } = req.user;
const contact = await GetContactService({
name,
number,
companyId
});
return res.status(200).json(contact);
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const newContact: ContactData = req.body;
newContact.number = newContact.number.replace("-", "").replace(" ", "");
const schema = Yup.object().shape({
name: Yup.string().required(),
/*number: Yup.string()
.required()
.matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")*/
});
try {
await schema.validate(newContact);
} catch (err: any) {
throw new AppError(err.message);
}
await CheckIsValidContact(newContact.number, companyId);
const validNumber = await CheckContactNumber(newContact.number, companyId);
const number = validNumber.jid.replace(/\D/g, "");
newContact.number = number;
// Check if the contact already exists
const existingContact = await Contact.findOne({
where: {
number: newContact.number,
companyId
}
});
if (existingContact) {
// Contact already exists, send the existing contact data as the response
return res.status(200).json({ alreadyExists: true, existingContact });
}
/**
* Código desabilitado por demora no retorno
*/
// const profilePicUrl = await GetProfilePicUrl(validNumber.jid, companyId);
const contact = await CreateContactService({
...newContact,
// profilePicUrl,
companyId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-contact`, {
action: "create",
contact
});
return res.status(200).json(contact);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { contactId } = req.params;
const { companyId } = req.user;
const contact = await ShowContactService(contactId, companyId);
return res.status(200).json(contact);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const contactData: ContactData = req.body;
const { companyId } = req.user;
const schema = Yup.object().shape({
name: Yup.string(),
/*number: Yup.string().matches(
/^\d+$/,
"Invalid number format. Only numbers is allowed."
)*/
});
try {
await schema.validate(contactData);
} catch (err: any) {
throw new AppError(err.message);
}
/*await CheckIsValidContact(contactData.number, companyId);
const validNumber = await CheckContactNumber(contactData.number, companyId);
const number = validNumber.jid.replace(/\D/g, "");
contactData.number = number;
*/
const { contactId } = req.params;
const contact = await UpdateContactService({
contactData,
contactId,
companyId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-contact`, {
action: "update",
contact
});
return res.status(200).json(contact);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { contactId } = req.params;
const { companyId } = req.user;
await ShowContactService(contactId, companyId);
await DeleteContactService(contactId);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-contact`, {
action: "delete",
contactId
});
return res.status(200).json({ message: "Contact deleted" });
};
export const list = async (req: Request, res: Response): Promise<Response> => {
const { name } = req.query as unknown as SearchContactParams;
const { companyId } = req.user;
const contacts = await SimpleListService({ name, companyId });
return res.json(contacts);
};
export const upload = async (req: Request, res: Response) => {
const files = req.files as Express.Multer.File[];
const file: Express.Multer.File = head(files) as Express.Multer.File;
const { companyId } = req.user;
const response = await ImportContacts(companyId, file);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-contact`, {
action: "create",
records: response
});
return res.status(200).json(response);
};
export const getContactVcard = async (
req: Request,
res: Response
): Promise<Response> => {
const { name, number } = req.query as IndexGetContactQuery;
const { companyId } = req.user;
let vNumber = number;
const numberDDI = vNumber.toString().substr(0, 2);
const numberDDD = vNumber.toString().substr(2, 2);
const numberUser = vNumber.toString().substr(-8, 8);
if (numberDDD <= '30' && numberDDI === '55') {
console.log("menor 30")
vNumber = `${numberDDI + numberDDD + 9 + numberUser}@s.whatsapp.net`;
} else if (numberDDD > '30' && numberDDI === '55') {
console.log("maior 30")
vNumber = `${numberDDI + numberDDD + numberUser}@s.whatsapp.net`;
} else {
vNumber = `${number}@s.whatsapp.net`;
}
console.log(vNumber);
const contact = await GetContactService({
name,
number,
companyId
});
return res.status(200).json(contact);
};

View File

@ -0,0 +1,159 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import ListService from "../services/ContactListService/ListService";
import CreateService from "../services/ContactListService/CreateService";
import ShowService from "../services/ContactListService/ShowService";
import UpdateService from "../services/ContactListService/UpdateService";
import DeleteService from "../services/ContactListService/DeleteService";
import FindService from "../services/ContactListService/FindService";
import { head } from "lodash";
import ContactList from "../models/ContactList";
import AppError from "../errors/AppError";
import { ImportContacts } from "../services/ContactListService/ImportContacts";
type IndexQuery = {
searchParam: string;
pageNumber: string;
companyId: string | number;
};
type StoreData = {
name: string;
companyId: string;
};
type FindParams = {
companyId: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { companyId } = req.user;
const { records, count, hasMore } = await ListService({
searchParam,
pageNumber,
companyId
});
return res.json({ records, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const data = req.body as StoreData;
const schema = Yup.object().shape({
name: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const record = await CreateService({
...data,
companyId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-ContactList`, {
action: "create",
record
});
return res.status(200).json(record);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const record = await ShowService(id);
return res.status(200).json(record);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const data = req.body as StoreData;
const { companyId } = req.user;
const schema = Yup.object().shape({
name: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const { id } = req.params;
const record = await UpdateService({
...data,
id
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-ContactList`, {
action: "update",
record
});
return res.status(200).json(record);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user;
await DeleteService(id);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-ContactList`, {
action: "delete",
id
});
return res.status(200).json({ message: "Contact list deleted" });
};
export const findList = async (
req: Request,
res: Response
): Promise<Response> => {
const params = req.query as FindParams;
const records: ContactList[] = await FindService(params);
return res.status(200).json(records);
};
export const upload = async (req: Request, res: Response) => {
const files = req.files as Express.Multer.File[];
const file: Express.Multer.File = head(files) as Express.Multer.File;
const { id } = req.params;
const { companyId } = req.user;
const response = await ImportContacts(+id, companyId, file);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-ContactListItem-${+id}`, {
action: "reload",
records: response
});
return res.status(200).json(response);
};

View File

@ -0,0 +1,145 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import ListService from "../services/ContactListItemService/ListService";
import CreateService from "../services/ContactListItemService/CreateService";
import ShowService from "../services/ContactListItemService/ShowService";
import UpdateService from "../services/ContactListItemService/UpdateService";
import DeleteService from "../services/ContactListItemService/DeleteService";
import FindService from "../services/ContactListItemService/FindService";
import ContactListItem from "../models/ContactListItem";
import AppError from "../errors/AppError";
type IndexQuery = {
searchParam: string;
pageNumber: string;
companyId: string | number;
contactListId: string | number;
};
type StoreData = {
name: string;
number: string;
contactListId: number;
companyId?: string;
email?: string;
};
type FindParams = {
companyId: number;
contactListId: number;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber, contactListId } = req.query as IndexQuery;
const { companyId } = req.user;
const { contacts, count, hasMore } = await ListService({
searchParam,
pageNumber,
companyId,
contactListId
});
return res.json({ contacts, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const data = req.body as StoreData;
const schema = Yup.object().shape({
name: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const record = await CreateService({
...data,
companyId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-ContactListItem`, {
action: "create",
record
});
return res.status(200).json(record);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const record = await ShowService(id);
return res.status(200).json(record);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const data = req.body as StoreData;
const { companyId } = req.user;
const schema = Yup.object().shape({
name: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const { id } = req.params;
const record = await UpdateService({
...data,
id
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-ContactListItem`, {
action: "update",
record
});
return res.status(200).json(record);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user;
await DeleteService(id);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-ContactListItem`, {
action: "delete",
id
});
return res.status(200).json({ message: "Contact deleted" });
};
export const findList = async (
req: Request,
res: Response
): Promise<Response> => {
const params = req.query as unknown as FindParams;
const records: ContactListItem[] = await FindService(params);
return res.status(200).json(records);
};

View File

@ -0,0 +1,55 @@
import { Request, Response } from 'express';
import DashboardDataService, {
DashboardData,
Params,
} from '../services/ReportService/DashbardDataService';
import { TicketsAttendance } from '../services/ReportService/TicketsAttendance';
import { TicketsDayService } from '../services/ReportService/TicketsDayService';
type IndexQuery = {
initialDate: string;
finalDate: string;
companyId: number | any;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const params: Params = req.query;
const { companyId } = req.user;
let daysInterval = 3;
const dashboardData: DashboardData = await DashboardDataService(
companyId,
params,
);
return res.status(200).json(dashboardData);
};
export const reportsUsers = async (
req: Request,
res: Response,
): Promise<Response> => {
const { initialDate, finalDate, companyId } = req.query as IndexQuery;
const { data } = await TicketsAttendance({
initialDate,
finalDate,
companyId,
});
return res.json({ data });
};
export const reportsDay = async (
req: Request,
res: Response,
): Promise<Response> => {
const { initialDate, finalDate, companyId } = req.query as IndexQuery;
const { count, data } = await TicketsDayService({
initialDate,
finalDate,
companyId,
});
return res.json({ count, data });
};

View File

@ -0,0 +1,155 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import AppError from "../errors/AppError";
import { head } from "lodash";
import CreateService from "../services/FileServices/CreateService";
import ListService from "../services/FileServices/ListService";
import UpdateService from "../services/FileServices/UpdateService";
import ShowService from "../services/FileServices/ShowService";
import DeleteService from "../services/FileServices/DeleteService";
import SimpleListService from "../services/FileServices/SimpleListService";
import DeleteAllService from "../services/FileServices/DeleteAllService";
import ShowTicketService from "../services/TicketServices/ShowTicketService";
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
import FilesOptions from "../models/FilesOptions";
type IndexQuery = {
searchParam?: string;
pageNumber?: string | number;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { pageNumber, searchParam } = req.query as IndexQuery;
const { companyId } = req.user;
const { files, count, hasMore } = await ListService({
searchParam,
pageNumber,
companyId
});
return res.json({ files, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { name, message, options } = req.body;
const { companyId } = req.user;
const fileList = await CreateService({
name,
message,
options,
companyId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company${companyId}-file`, {
action: "create",
fileList
});
return res.status(200).json(fileList);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { fileId } = req.params;
const { companyId } = req.user;
const file = await ShowService(fileId, companyId);
return res.status(200).json(file);
};
export const uploadMedias = async (req: Request, res: Response): Promise<Response> => {
const { fileId, id, mediaType } = req.body;
const files = req.files as Express.Multer.File[];
const file = head(files);
try {
let fileOpt
if (files.length > 0) {
for (const [index, file] of files.entries()) {
fileOpt = await FilesOptions.findOne({
where: {
fileId,
id: Array.isArray(id)? id[index] : id
}
});
fileOpt.update({
path: file.filename.replace('/','-'),
mediaType: Array.isArray(mediaType)? mediaType[index] : mediaType
}) ;
}
}
return res.send({ mensagem: "Arquivos atualizados" });
} catch (err: any) {
throw new AppError(err.message);
}
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
if (req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
const { fileId } = req.params;
const fileData = req.body;
const { companyId } = req.user;
const fileList = await UpdateService({ fileData, id: fileId, companyId });
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company${companyId}-file`, {
action: "update",
fileList
});
return res.status(200).json(fileList);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { fileId } = req.params;
const { companyId } = req.user;
await DeleteService(fileId, companyId);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company${companyId}-file`, {
action: "delete",
fileId
});
return res.status(200).json({ message: "File List deleted" });
};
export const removeAll = async (
req: Request,
res: Response
): Promise<Response> => {
const { companyId } = req.user;
await DeleteAllService(companyId);
return res.send();
};
export const list = async (req: Request, res: Response): Promise<Response> => {
const { searchParam } = req.query as IndexQuery;
const { companyId } = req.user;
const ratings = await SimpleListService({ searchParam, companyId });
return res.json(ratings);
};

View File

@ -0,0 +1,25 @@
import { v4 as uuid } from "uuid";
import { Request, Response } from "express";
import SendMail from "../services/ForgotPassWordServices/SendMail";
import ResetPassword from "../services/ResetPasswordService/ResetPassword";
type IndexQuery = { email?: string; token?: string; password?: string };
export const store = async (req: Request, res: Response): Promise<Response> => {
const { email } = req.params as IndexQuery;
const TokenSenha = uuid();
const forgotPassword = await SendMail(email, TokenSenha);
if (!forgotPassword) {
return res.status(200).json({ message: "E-mail enviado com sucesso" });
}
return res.status(404).json({ error: "E-mail enviado com sucesso" });
};
export const resetPasswords = async (
req: Request,
res: Response
): Promise<Response> => {
const { email, token, password } = req.params as IndexQuery;
const resetPassword = await ResetPassword(email, token, password);
if (!resetPassword) {
return res.status(200).json({ message: "Senha redefinida com sucesso" });
}
return res.status(404).json({ error: "Verifique o Token informado" });
};

View File

@ -0,0 +1,131 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import ListService from "../services/HelpServices/ListService";
import CreateService from "../services/HelpServices/CreateService";
import ShowService from "../services/HelpServices/ShowService";
import UpdateService from "../services/HelpServices/UpdateService";
import DeleteService from "../services/HelpServices/DeleteService";
import FindService from "../services/HelpServices/FindService";
import Help from "../models/Help";
import AppError from "../errors/AppError";
type IndexQuery = {
searchParam: string;
pageNumber: string;
};
type StoreData = {
title: string;
description: string;
video?: string;
link?: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { records, count, hasMore } = await ListService({
searchParam,
pageNumber
});
return res.json({ records, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const data = req.body as StoreData;
const schema = Yup.object().shape({
title: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err) {
throw new AppError(err.message);
}
const record = await CreateService({
...data
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-help`, {
action: "create",
record
});
return res.status(200).json(record);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const record = await ShowService(id);
return res.status(200).json(record);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const data = req.body as StoreData;
const { companyId } = req.user;
const schema = Yup.object().shape({
title: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err) {
throw new AppError(err.message);
}
const { id } = req.params;
const record = await UpdateService({
...data,
id
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-help`, {
action: "update",
record
});
return res.status(200).json(record);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user;
await DeleteService(id);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-help`, {
action: "delete",
id
});
return res.status(200).json({ message: "Help deleted" });
};
export const findList = async (
req: Request,
res: Response
): Promise<Response> => {
const records: Help[] = await FindService();
return res.status(200).json(records);
};

View File

@ -0,0 +1,148 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import ListService from "../services/HubNotificaMeService/ListService";
import CreateService from "../services/HubNotificaMeService/CreateService";
import ShowService from "../services/HubNotificaMeService/ShowService";
import UpdateService from "../services/HubNotificaMeService/UpdateService";
import DeleteService from "../services/HubNotificaMeService/DeleteService";
import FindService from "../services/HubNotificaMeService/FindService";
import HubNotificaMe from "../models/HubNotificaMe";
import { head } from "lodash";
import fs from "fs";
import path from "path";
import AppError from "../errors/AppError";
type IndexQuery = {
searchParam: string;
pageNumber: string;
};
type StoreData = {
nome: string;
token: string;
tipo: string;
};
type FindParams = {
companyId: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { companyId } = req.user;
const { records, count, hasMore } = await ListService({
searchParam,
pageNumber,
companyId
});
return res.json({ records, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const data = req.body as StoreData;
// Certifique-se de que o tipo foi fornecido
const schema = Yup.object().shape({
nome: Yup.string().required(),
token: Yup.string().required(),
tipo: Yup.string().oneOf(["Facebook", "Instagram"], "Tipo inválido").required("Tipo é obrigatório"), // Validação do tipo
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const record = await CreateService({
...data,
companyId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-hubnotificame`, {
action: "create",
record
});
return res.status(200).json(record);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const record = await ShowService(id);
return res.status(200).json(record);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const data = req.body as StoreData;
const { companyId } = req.user;
const schema = Yup.object().shape({
nome: Yup.string().required(),
token: Yup.string().required(),
tipo: Yup.string().oneOf(["Facebook", "Instagram"], "Tipo inválido").required("Tipo é obrigatório"), // Validação do tipo
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const { id } = req.params;
const record = await UpdateService({
...data,
id,
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-hubnotificame`, {
action: "update",
record
});
return res.status(200).json(record);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user;
await DeleteService(id);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-hubnotificame`, {
action: "delete",
id
});
return res.status(200).json({ message: "Contact deleted" });
};
export const findList = async (
req: Request,
res: Response
): Promise<Response> => {
const params = req.query as FindParams;
const records: HubNotificaMe[] = await FindService(params);
return res.status(200).json(records);
};

View File

@ -0,0 +1,10 @@
import { Request, Response } from "express";
import ImportContactsService from "../services/WbotServices/ImportContactsService";
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
await ImportContactsService(companyId);
return res.status(200).json({ message: "contacts imported" });
};

View File

@ -0,0 +1,172 @@
import * as Yup from "yup";
import { Request, Response } from "express";
// import { getIO } from "../libs/socket";
import AppError from "../errors/AppError";
import Invoices from "../models/Invoices";
import CreatePlanService from "../services/PlanService/CreatePlanService";
import UpdatePlanService from "../services/PlanService/UpdatePlanService";
import ShowPlanService from "../services/PlanService/ShowPlanService";
import DeletePlanService from "../services/PlanService/DeletePlanService";
import FindAllInvoiceService from "../services/InvoicesService/FindAllInvoiceService";
import ListInvoicesServices from "../services/InvoicesService/ListInvoicesServices";
import ShowInvoceService from "../services/InvoicesService/ShowInvoiceService";
import UpdateInvoiceService from "../services/InvoicesService/UpdateInvoiceService";
type IndexQuery = {
searchParam: string;
pageNumber: string;
};
type StorePlanData = {
name: string;
id?: number | string;
users: number | 0;
connections: number | 0;
queues: number | 0;
value: number;
};
type UpdateInvoiceData = {
status: string;
id?: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { invoices, count, hasMore } = await ListInvoicesServices({
searchParam,
pageNumber
});
return res.json({ invoices, count, hasMore });
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { Invoiceid } = req.params;
const invoice = await ShowInvoceService(Invoiceid);
return res.status(200).json(invoice);
};
export const list = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const invoice: Invoices[] = await FindAllInvoiceService(companyId);
return res.status(200).json(invoice);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const InvoiceData: UpdateInvoiceData = req.body;
const schema = Yup.object().shape({
name: Yup.string()
});
try {
await schema.validate(InvoiceData);
} catch (err) {
throw new AppError(err.message);
}
const { id, status } = InvoiceData;
const plan = await UpdateInvoiceService({
id,
status,
});
// const io = getIO();
// io.emit("plan", {
// action: "update",
// plan
// });
return res.status(200).json(plan);
};
/* export const store = async (req: Request, res: Response): Promise<Response> => {
const newPlan: StorePlanData = req.body;
const schema = Yup.object().shape({
name: Yup.string().required()
});
try {
await schema.validate(newPlan);
} catch (err) {
throw new AppError(err.message);
}
const plan = await CreatePlanService(newPlan);
// const io = getIO();
// io.emit("plan", {
// action: "create",
// plan
// });
return res.status(200).json(plan);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const plan = await ShowPlanService(id);
return res.status(200).json(plan);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const planData: UpdateInvoiceData = req.body;
const schema = Yup.object().shape({
name: Yup.string()
});
try {
await schema.validate(planData);
} catch (err) {
throw new AppError(err.message);
}
const { id, name, users, connections, queues, value } = planData;
const plan = await UpdatePlanService({
id,
name,
users,
connections,
queues,
value
});
// const io = getIO();
// io.emit("plan", {
// action: "update",
// plan
// });
return res.status(200).json(plan);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const plan = await DeletePlanService(id);
return res.status(200).json(plan);
}; */

View File

@ -0,0 +1,370 @@
import { Request, Response } from "express";
import AppError from "../errors/AppError";
import formatBody from "../helpers/Mustache";
import SetTicketMessagesAsRead from "../helpers/SetTicketMessagesAsRead";
import { getIO } from "../libs/socket";
import Ticket from "../models/Ticket";
import Message from "../models/Message";
import Queue from "../models/Queue";
import User from "../models/User";
import Whatsapp from "../models/Whatsapp";
import { lookup } from 'mime-types';
import { isNil } from "lodash";
import QuickMessage from "../models/QuickMessage";
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
import SendWhatsAppReaction from "../services/WbotServices/SendWhatsAppReaction";
import ListMessagesService from "../services/MessageServices/ListMessagesService";
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
import ShowTicketService from "../services/TicketServices/ShowTicketService";
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
import CheckContactNumber from "../services/WbotServices/CheckNumber";
import DeleteWhatsAppMessage from "../services/WbotServices/DeleteWhatsAppMessage";
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
import ShowContactService from "../services/ContactServices/ShowContactService";
import SendWhatsAppMedia from "../services/WbotServices/SendWhatsAppMedia";
//import SendWhatsAppMediaInternal from "../services/WbotServices/SendWhatsAppMediaInternal";
import path from "path";
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
import EditWhatsAppMessage from "../services/WbotServices/EditWhatsAppMessage";
import ShowMessageService, { GetWhatsAppFromMessage } from "../services/MessageServices/ShowMessageService";
type IndexQuery = {
pageNumber: string;
};
type MessageData = {
body: string;
fromMe: boolean;
read: boolean;
quotedMsg?: Message;
number?: string;
closeTicket?: true;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { ticketId } = req.params;
const { pageNumber } = req.query as IndexQuery;
const { companyId, profile } = req.user;
const queues: number[] = [];
if (profile !== "admin") {
const user = await User.findByPk(req.user.id, {
include: [{ model: Queue, as: "queues" }]
});
user.queues.forEach(queue => {
queues.push(queue.id);
});
}
const { count, messages, ticket, hasMore } = await ListMessagesService({
pageNumber,
ticketId,
companyId,
queues
});
SetTicketMessagesAsRead(ticket);
return res.json({ count, messages, ticket, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { ticketId } = req.params;
const { body, quotedMsg }: MessageData = req.body;
const medias = req.files as Express.Multer.File[];
const { companyId } = req.user;
const ticket = await ShowTicketService(ticketId, companyId);
SetTicketMessagesAsRead(ticket);
console.log('bodyyyyyyyyyy:', body)
if (medias) {
await Promise.all(
medias.map(async (media: Express.Multer.File, index) => {
await SendWhatsAppMedia({ media, ticket, body: Array.isArray(body) ? body[index] : body });
})
);
} else {
const send = await SendWhatsAppMessage({ body, ticket, quotedMsg });
}
return res.send();
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { messageId } = req.params;
const { companyId } = req.user;
const message = await DeleteWhatsAppMessage(messageId);
const io = getIO();
io.to(message.ticketId.toString()).emit(`company-${companyId}-appMessage`, {
action: "update",
message
});
return res.send();
};
export const send = async (req: Request, res: Response): Promise<Response> => {
const { whatsappId } = req.params as unknown as { whatsappId: number };
const messageData: MessageData = req.body;
const medias = req.files as Express.Multer.File[];
console.log('messageData;', messageData)
try {
const whatsapp = await Whatsapp.findByPk(whatsappId);
if (!whatsapp) {
throw new Error("Não foi possível realizar a operação");
}
if (messageData.number === undefined) {
throw new Error("O número é obrigatório");
}
const numberToTest = messageData.number;
const body = messageData.body;
const companyId = whatsapp.companyId;
const CheckValidNumber = await CheckContactNumber(numberToTest, companyId);
const number = CheckValidNumber.jid.replace(/\D/g, "");
const profilePicUrl = await GetProfilePicUrl(
number,
companyId
);
const contactData = {
name: `${number}`,
number,
profilePicUrl,
isGroup: false,
companyId
};
const contact = await CreateOrUpdateContactService(contactData);
const ticket = await FindOrCreateTicketService(contact, whatsapp.id!, 0, companyId);
if (medias) {
await Promise.all(
medias.map(async (media: Express.Multer.File) => {
await req.app.get("queues").messageQueue.add(
"SendMessage",
{
whatsappId,
data: {
number,
body: body ? formatBody(body, contact) : media.originalname,
mediaPath: media.path,
fileName: media.originalname
}
},
{ removeOnComplete: true, attempts: 3 }
);
})
);
} else {
await SendWhatsAppMessage({ body: formatBody(body, contact), ticket });
await ticket.update({
lastMessage: body,
});
}
if (messageData.closeTicket) {
setTimeout(async () => {
await UpdateTicketService({
ticketId: ticket.id,
ticketData: { status: "closed" },
companyId
});
}, 1000);
}
SetTicketMessagesAsRead(ticket);
return res.send({ mensagem: "Mensagem enviada" });
} catch (err: any) {
if (Object.keys(err).length === 0) {
throw new AppError(
"Não foi possível enviar a mensagem, tente novamente em alguns instantes"
);
} else {
throw new AppError(err.message);
}
}
};
export const addReaction = async (req: Request, res: Response): Promise<Response> => {
try {
const {messageId} = req.params;
const {type} = req.body; // O tipo de reação, por exemplo, 'like', 'heart', etc.
const {companyId, id} = req.user;
const message = await Message.findByPk(messageId);
const ticket = await Ticket.findByPk(message.ticketId, {
include: ["contact"]
});
if (!message) {
return res.status(404).send({message: "Mensagem não encontrada"});
}
// Envia a reação via WhatsApp
const reactionResult = await SendWhatsAppReaction({
messageId: messageId,
ticket: ticket,
reactionType: type
});
// Atualiza a mensagem com a nova reação no banco de dados (opcional, dependendo da necessidade)
const updatedMessage = await message.update({
reactions: [...message.reactions, {type: type, userId: id}]
});
const io = getIO();
io.to(message.ticketId.toString()).emit(`company-${companyId}-appMessage`, {
action: "update",
message
});
return res.status(200).send({
message: 'Reação adicionada com sucesso!',
reactionResult,
reactions: updatedMessage.reactions
});
} catch (error) {
console.error('Erro ao adicionar reação:', error);
if (error instanceof AppError) {
return res.status(400).send({message: error.message});
}
return res.status(500).send({message: 'Erro ao adicionar reação', error: error.message});
}
};
function obterNomeEExtensaoDoArquivo(url) {
var urlObj = new URL(url);
var pathname = urlObj.pathname;
var filename = pathname.split('/').pop();
var parts = filename.split('.');
var nomeDoArquivo = parts[0];
var extensao = parts[1];
return `${nomeDoArquivo}.${extensao}`;
}
export const forwardMessage = async (
req: Request,
res: Response
): Promise<Response> => {
const { quotedMsg, signMessage, messageId, contactId } = req.body;
const { id: userId, companyId } = req.user;
const requestUser = await User.findByPk(userId);
if (!messageId || !contactId) {
return res.status(200).send("MessageId or ContactId not found");
}
const message = await ShowMessageService(messageId);
const contact = await ShowContactService(contactId, companyId);
if (!message) {
return res.status(404).send("Message not found");
}
if (!contact) {
return res.status(404).send("Contact not found");
}
const whatsAppConnectionId = await GetWhatsAppFromMessage(message);
if (!whatsAppConnectionId) {
return res.status(404).send('Whatsapp from message not found');
}
const ticket = await ShowTicketService(message.ticketId, message.companyId);
const createTicket = await FindOrCreateTicketService(
contact,
ticket?.whatsappId,
0,
ticket.companyId,
contact.isGroup ? contact : null,
);
let ticketData;
if (isNil(createTicket?.queueId)) {
ticketData = {
status: createTicket.isGroup ? "group" : "open",
userId: requestUser.id,
queueId: ticket.queueId
}
} else {
ticketData = {
status: createTicket.isGroup ? "group" : "open",
userId: requestUser.id
}
}
await UpdateTicketService({
ticketData,
ticketId: createTicket.id,
companyId: createTicket.companyId
});
let body = message.body;
if (message.mediaType === 'conversation' || message.mediaType === 'extendedTextMessage') {
await SendWhatsAppMessage({ body, ticket: createTicket, quotedMsg, isForwarded: message.fromMe ? false : true });
} else {
const mediaUrl = message.mediaUrl.replace(`:${process.env.PORT}`, '');
const fileName = obterNomeEExtensaoDoArquivo(mediaUrl);
if (body === fileName) {
body = "";
}
const publicFolder = path.join(__dirname, '..', '..', '..', 'backend', 'public');
const filePath = path.join(publicFolder, `company${createTicket.companyId}`, fileName)
const mediaSrc = {
fieldname: 'medias',
originalname: fileName,
encoding: '7bit',
mimetype: message.mediaType,
filename: fileName,
path: filePath
} as Express.Multer.File
await SendWhatsAppMedia({ media: mediaSrc, ticket: createTicket, body, isForwarded: message.fromMe ? false : true });
}
return res.send();
}
export const edit = async (req: Request, res: Response): Promise<Response> => {
const { messageId } = req.params;
const { companyId } = req.user;
const { body }: MessageData = req.body;
console.log(body)
const { ticket , message } = await EditWhatsAppMessage({messageId, body});
const io = getIO();
io.emit(`company-${companyId}-appMessage`, {
action:"update",
message,
ticket: ticket,
contact: ticket.contact,
});
return res.send();
}

View File

@ -0,0 +1,105 @@
import { Request, Response } from "express";
import User from "../models/User";
import { getIO } from "../libs/socket";
import Contact from "../models/Contact";
import Ticket from "../models/Ticket";
import Whatsapp from "../models/Whatsapp";
import { SendMediaMessageService } from "../services/HubServices/SendMediaMessageHubService";
import { SendTextMessageService } from "../services/HubServices/SendTextMessageHubService";
import CreateHubTicketService from "../services/HubServices/CreateHubTicketService";
interface TicketData {
contactId: number;
status: string;
queueId: number;
userId: number;
channel: string;
companyId: number;
}
export const send = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
console.log('CompanyId do usuário autenticado:', companyId); // Verifique se companyId está correto aqui
const { body: message } = req.body;
const { ticketId } = req.params;
const medias = req.files as Express.Multer.File[];
console.log("sending hub message controller");
const ticket = await Ticket.findOne({
where: { id: ticketId, companyId }, // Filtro pelo companyId
include: [
{
model: Contact,
as: "contact",
attributes: ["number", "messengerId", "instagramId"]
},
{
model: Whatsapp,
as: "whatsapp",
attributes: ["qrcode", "type", "companyId"]
}
]
});
if (!ticket) {
return res.status(404).json({ message: "Ticket not found" });
}
try {
if (medias) {
await Promise.all(
medias.map(async (media: Express.Multer.File) => {
await SendMediaMessageService(
media,
message,
ticket.id,
ticket.contact,
ticket.whatsapp,
companyId
);
})
);
} else {
await SendTextMessageService(
message,
ticket.id,
ticket.contact,
ticket.whatsapp,
companyId
);
}
return res.status(200).json({ message: "Message sent" });
} catch (error) {
console.log(error);
return res.status(400).json({ message: error });
}
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { contactId, status, userId, channel }: TicketData = req.body;
const { companyId } = req.user; // Obtendo o companyId do usuário autenticado
const ticket = await CreateHubTicketService({
contactId,
status,
userId,
channel,
companyId // Passando o companyId na criação do ticket
});
const io = getIO();
io.to(ticket.status).emit("ticket", {
action: "update",
ticket
});
return res.status(200).json(ticket);
};

View File

@ -0,0 +1,146 @@
import * as Yup from "yup";
import { Request, Response } from "express";
// import { getIO } from "../libs/socket";
import AppError from "../errors/AppError";
import Plan from "../models/Plan";
import ListPlansService from "../services/PlanService/ListPlansService";
import CreatePlanService from "../services/PlanService/CreatePlanService";
import UpdatePlanService from "../services/PlanService/UpdatePlanService";
import ShowPlanService from "../services/PlanService/ShowPlanService";
import FindAllPlanServiceRegister from "../services/PlanService/FindAllPlanServiceRegister";
import FindAllPlanService from "../services/PlanService/FindAllPlanService";
import DeletePlanService from "../services/PlanService/DeletePlanService";
type IndexQuery = {
searchParam: string;
pageNumber: string;
};
type StorePlanData = {
name: string;
id?: number | string;
users: number | 0;
connections: number | 0;
queues: number | 0;
value: number;
useCampaigns?: boolean;
useSchedules?: boolean;
useInternalChat?: boolean;
useExternalApi?: boolean;
useKanban?: boolean;
useOpenAi?: boolean;
useIntegrations?: boolean;
useInternal?: boolean;
};
type UpdatePlanData = {
name: string;
id?: number | string;
users?: number;
connections?: number;
queues?: number;
value?: number;
useCampaigns?: boolean;
useSchedules?: boolean;
useInternalChat?: boolean;
useExternalApi?: boolean;
useKanban?: boolean;
useOpenAi?: boolean;
useIntegrations?: boolean;
useInternal?: boolean;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { plans, count, hasMore } = await ListPlansService({
searchParam,
pageNumber
});
return res.json({ plans, count, hasMore });
};
export const list = async (req: Request, res: Response): Promise<Response> => {
const plans: Plan[] = await FindAllPlanService();
return res.status(200).json(plans);
};
export const register = async (req: Request, res: Response): Promise<Response> => {
const plans: Plan[] = await FindAllPlanServiceRegister();
return res.status(200).json(plans);
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const newPlan: StorePlanData = req.body;
const schema = Yup.object().shape({
name: Yup.string().required()
});
try {
await schema.validate(newPlan);
} catch (err) {
throw new AppError(err.message);
}
const plan = await CreatePlanService(newPlan);
// const io = getIO();
// io.emit("plan", {
// action: "create",
// plan
// });
return res.status(200).json(plan);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const plan = await ShowPlanService(id);
return res.status(200).json(plan);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const planData: UpdatePlanData = req.body;
const schema = Yup.object().shape({
name: Yup.string()
});
try {
await schema.validate(planData);
} catch (err) {
throw new AppError(err.message);
}
const plan = await UpdatePlanService(planData);
// const io = getIO();
// io.emit("plan", {
// action: "update",
// plan
// });
return res.status(200).json(plan);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const plan = await DeletePlanService(id);
return res.status(200).json(plan);
};

View File

@ -0,0 +1,114 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import CreatePromptService from "../services/PromptServices/CreatePromptService";
import DeletePromptService from "../services/PromptServices/DeletePromptService";
import ListPromptsService from "../services/PromptServices/ListPromptsService";
import ShowPromptService from "../services/PromptServices/ShowPromptService";
import UpdatePromptService from "../services/PromptServices/UpdatePromptService";
import Whatsapp from "../models/Whatsapp";
import { verify } from "jsonwebtoken";
import authConfig from "../config/auth";
interface TokenPayload {
id: string;
username: string;
profile: string;
companyId: number;
iat: number;
exp: number;
}
type IndexQuery = {
searchParam?: string;
pageNumber?: string | number;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { pageNumber, searchParam } = req.query as IndexQuery;
const authHeader = req.headers.authorization;
const [, token] = authHeader.split(" ");
const decoded = verify(token, authConfig.secret);
const { companyId } = decoded as TokenPayload;
const { prompts, count, hasMore } = await ListPromptsService({ searchParam, pageNumber, companyId });
return res.status(200).json({ prompts, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const authHeader = req.headers.authorization;
const [, token] = authHeader.split(" ");
const decoded = verify(token, authConfig.secret);
const { companyId } = decoded as TokenPayload;
const { name, apiKey, prompt, maxTokens, temperature, promptTokens, completionTokens, totalTokens, queueId, maxMessages,voice,voiceKey,voiceRegion } = req.body;
const promptTable = await CreatePromptService({ name, apiKey, prompt, maxTokens, temperature, promptTokens, completionTokens, totalTokens, queueId, maxMessages, companyId,voice,voiceKey,voiceRegion });
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit("prompt", {
action: "update",
prompt: promptTable
});
return res.status(200).json(promptTable);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { promptId } = req.params;
const authHeader = req.headers.authorization;
const [, token] = authHeader.split(" ");
const decoded = verify(token, authConfig.secret);
const { companyId } = decoded as TokenPayload;
const prompt = await ShowPromptService({ promptId, companyId });
return res.status(200).json(prompt);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const { promptId } = req.params;
const promptData = req.body;
const authHeader = req.headers.authorization;
const [, token] = authHeader.split(" ");
const decoded = verify(token, authConfig.secret);
const { companyId } = decoded as TokenPayload;
const prompt = await UpdatePromptService({ promptData, promptId: promptId, companyId });
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit("prompt", {
action: "update",
prompt
});
return res.status(200).json(prompt);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { promptId } = req.params;
const authHeader = req.headers.authorization;
const [, token] = authHeader.split(" ");
const decoded = verify(token, authConfig.secret);
const { companyId } = decoded as TokenPayload;
try {
const { count } = await Whatsapp.findAndCountAll({ where: { promptId: +promptId, companyId } });
if (count > 0) return res.status(200).json({ message: "Não foi possível excluir! Verifique se este prompt está sendo usado nas conexões Whatsapp!" });
await DeletePromptService(promptId, companyId);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit("prompt", {
action: "delete",
intelligenceId: +promptId
});
return res.status(200).json({ message: "Prompt deleted" });
} catch (err) {
return res.status(500).json({ message: "Não foi possível excluir! Verifique se este prompt está sendo usado!" });
}
};

View File

@ -0,0 +1,157 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import CreateQueueService from "../services/QueueService/CreateQueueService";
import DeleteQueueService from "../services/QueueService/DeleteQueueService";
import ListQueuesService from "../services/QueueService/ListQueuesService";
import ShowQueueService from "../services/QueueService/ShowQueueService";
import UpdateQueueService from "../services/QueueService/UpdateQueueService";
import { isNil } from "lodash";
import Queue from "../models/Queue";
import { head } from "lodash";
import fs from "fs";
import path from "path";
import AppError from "../errors/AppError";
type QueueFilter = {
companyId: number;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { companyId: userCompanyId } = req.user;
const { companyId: queryCompanyId } = req.query as unknown as QueueFilter;
let companyId = userCompanyId;
if (!isNil(queryCompanyId)) {
companyId = +queryCompanyId;
}
const queues = await ListQueuesService({ companyId });
return res.status(200).json(queues);
};
export const mediaUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { queueId } = req.params;
const files = req.files as Express.Multer.File[];
const file = head(files);
try {
const queue = await Queue.findByPk(queueId);
queue.update({
mediaPath: file.filename,
mediaName: file.originalname
});
return res.send({ mensagem: "Arquivo Salvo" });
} catch (err: any) {
throw new AppError(err.message);
}
};
export const deleteMedia = async (
req: Request,
res: Response
): Promise<Response> => {
const { queueId } = req.params;
try {
const queue = await Queue.findByPk(queueId);
const filePath = path.resolve("public", queue.mediaPath);
const fileExists = fs.existsSync(filePath);
if (fileExists) {
fs.unlinkSync(filePath);
}
queue.mediaPath = null;
queue.mediaName = null;
await queue.save();
return res.send({ mensagem: "Arquivo excluído" });
} catch (err: any) {
throw new AppError(err.message);
}
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { name, color, greetingMessage, outOfHoursMessage, schedules, orderQueue, integrationId, promptId } =
req.body;
const { companyId } = req.user;
console.log("queue", integrationId, promptId)
const queue = await CreateQueueService({
name,
color,
greetingMessage,
companyId,
outOfHoursMessage,
schedules,
orderQueue: orderQueue === "" ? null : orderQueue,
integrationId: integrationId === "" ? null : integrationId,
promptId: promptId === "" ? null : promptId
});
const io = getIO();
io.emit(`company-${companyId}-queue`, {
action: "update",
queue
});
return res.status(200).json(queue);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { queueId } = req.params;
const { companyId } = req.user;
const queue = await ShowQueueService(queueId, companyId);
return res.status(200).json(queue);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const { queueId } = req.params;
const { companyId } = req.user;
const { name, color, greetingMessage, outOfHoursMessage, schedules, orderQueue, integrationId, promptId } =
req.body;
const queue = await UpdateQueueService(queueId, {
name,
color,
greetingMessage,
outOfHoursMessage,
schedules,
orderQueue: orderQueue === "" ? null : orderQueue,
integrationId: integrationId === "" ? null : integrationId,
promptId: promptId === "" ? null : promptId
}, companyId);
const io = getIO();
io.emit(`company-${companyId}-queue`, {
action: "update",
queue
});
return res.status(201).json(queue);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { queueId } = req.params;
const { companyId } = req.user;
await DeleteQueueService(queueId, companyId);
const io = getIO();
io.emit(`company-${companyId}-queue`, {
action: "delete",
queueId: +queueId
});
return res.status(200).send();
};

View File

@ -0,0 +1,99 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import CreateQueueIntegrationService from "../services/QueueIntegrationServices/CreateQueueIntegrationService";
import DeleteQueueIntegrationService from "../services/QueueIntegrationServices/DeleteQueueIntegrationService";
import ListQueueIntegrationService from "../services/QueueIntegrationServices/ListQueueIntegrationService";
import ShowQueueIntegrationService from "../services/QueueIntegrationServices/ShowQueueIntegrationService";
import UpdateQueueIntegrationService from "../services/QueueIntegrationServices/UpdateQueueIntegrationService";
type IndexQuery = {
searchParam: string;
pageNumber: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { companyId } = req.user;
const { queueIntegrations, count, hasMore } = await ListQueueIntegrationService({
searchParam,
pageNumber,
companyId
});
return res.status(200).json({ queueIntegrations, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { type, name, projectName, jsonContent, language, urlN8N,
typebotExpires,
typebotKeywordFinish,
typebotSlug,
typebotUnknownMessage,
typebotKeywordRestart,
typebotRestartMessage } = req.body;
const { companyId } = req.user;
const queueIntegration = await CreateQueueIntegrationService({
type, name, projectName, jsonContent, language, urlN8N, companyId,
typebotExpires,
typebotKeywordFinish,
typebotSlug,
typebotUnknownMessage,
typebotKeywordRestart,
typebotRestartMessage
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-queueIntegration`, {
action: "create",
queueIntegration
});
return res.status(200).json(queueIntegration);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { integrationId } = req.params;
const { companyId } = req.user;
const queueIntegration = await ShowQueueIntegrationService(integrationId, companyId);
return res.status(200).json(queueIntegration);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const { integrationId } = req.params;
const integrationData = req.body;
const { companyId } = req.user;
const queueIntegration = await UpdateQueueIntegrationService({ integrationData, integrationId, companyId });
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-queueIntegration`, {
action: "update",
queueIntegration
});
return res.status(201).json(queueIntegration);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { integrationId } = req.params;
const { companyId } = req.user;
await DeleteQueueIntegrationService(integrationId);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-queueIntegration`, {
action: "delete",
integrationId: +integrationId
});
return res.status(200).send();
};

View File

@ -0,0 +1,110 @@
import { Request, Response } from "express";
import CreateService from "../services/QueueOptionService/CreateService";
import ListService from "../services/QueueOptionService/ListService";
import UpdateService from "../services/QueueOptionService/UpdateService";
import ShowService from "../services/QueueOptionService/ShowService";
import DeleteService from "../services/QueueOptionService/DeleteService";
import { head } from "lodash";
import fs from "fs";
import path from "path";
import AppError from "../errors/AppError";
import QueueOption from "../models/QueueOption";
type FilterList = {
queueId: string | number;
queueOptionId: string | number;
parentId: string | number | boolean;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { queueId, queueOptionId, parentId } = req.query as FilterList;
const queueOptions = await ListService({ queueId, queueOptionId, parentId });
return res.json(queueOptions);
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const queueOptionData = req.body;
const queueOption = await CreateService(queueOptionData);
return res.status(200).json(queueOption);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { queueOptionId } = req.params;
const queueOption = await ShowService(queueOptionId);
return res.status(200).json(queueOption);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const { queueOptionId } = req.params
const queueOptionData = req.body;
const queueOption = await UpdateService(queueOptionId, queueOptionData);
return res.status(200).json(queueOption);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { queueOptionId } = req.params
await DeleteService(queueOptionId);
return res.status(200).json({ message: "Option Delected" });
};
export const mediaUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { queueOptionId } = req.params;
const files = req.files as Express.Multer.File[];
const file = head(files);
try {
const queue = await QueueOption.findByPk(queueOptionId);
queue.update({
mediaPath: file.filename,
mediaName: file.originalname
});
return res.send({ mensagem: "Arquivo Salvo" });
} catch (err: any) {
throw new AppError(err.message);
}
};
export const deleteMedia = async (
req: Request,
res: Response
): Promise<Response> => {
const { queueOptionId } = req.params;
try {
const queue = await QueueOption.findByPk(queueOptionId);
const filePath = path.resolve("public", queue.mediaPath);
const fileExists = fs.existsSync(filePath);
if (fileExists) {
fs.unlinkSync(filePath);
}
queue.mediaPath = null;
queue.mediaName = null;
await queue.save();
return res.send({ mensagem: "Arquivo excluído" });
} catch (err: any) {
throw new AppError(err.message);
}
};

View File

@ -0,0 +1,223 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import ListService from "../services/QuickMessageService/ListService";
import CreateService from "../services/QuickMessageService/CreateService";
import ShowService from "../services/QuickMessageService/ShowService";
import UpdateService from "../services/QuickMessageService/UpdateService";
import DeleteService from "../services/QuickMessageService/DeleteService";
import FindService from "../services/QuickMessageService/FindService";
import QuickMessage from "../models/QuickMessage";
import { head } from "lodash";
import fs from "fs";
import path from "path";
import AppError from "../errors/AppError";
type IndexQuery = {
searchParam: string;
pageNumber: string;
userId: string | number;
};
type StoreData = {
shortcode: string;
message: string;
userId: number | number;
geral: boolean;
};
type FindParams = {
companyId: string;
userId: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { companyId, id: userId } = req.user;
const { records, count, hasMore } = await ListService({
searchParam,
pageNumber,
companyId,
userId
});
return res.json({ records, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const data = req.body as StoreData;
const schema = Yup.object().shape({
shortcode: Yup.string().required(),
message: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const record = await CreateService({
...data,
companyId,
userId: req.user.id
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-quickmessage`, {
action: "create",
record
});
return res.status(200).json(record);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const record = await ShowService(id);
return res.status(200).json(record);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const data = req.body as StoreData;
const { companyId } = req.user;
const schema = Yup.object().shape({
shortcode: Yup.string().required(),
message: Yup.string().required()
});
try {
await schema.validate(data);
} catch (err: any) {
throw new AppError(err.message);
}
const { id } = req.params;
const record = await UpdateService({
...data,
userId: req.user.id,
id,
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-quickmessage`, {
action: "update",
record
});
return res.status(200).json(record);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user;
await DeleteService(id);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-quickmessage`, {
action: "delete",
id
});
return res.status(200).json({ message: "Contact deleted" });
};
export const findList = async (
req: Request,
res: Response
): Promise<Response> => {
const params = req.query as FindParams;
const records: QuickMessage[] = await FindService(params);
return res.status(200).json(records);
};
export const mediaUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const files = req.files as Express.Multer.File[];
const file = head(files);
try {
const quickmessage = await QuickMessage.findByPk(id);
quickmessage.update ({
mediaPath: file.filename,
mediaName: file.originalname
});
return res.send({ mensagem: "Arquivo Anexado" });
} catch (err: any) {
throw new AppError(err.message);
}
};
export const deleteMedia = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const { companyId } = req.user
try {
// Encontre a mensagem rápida
const quickmessage = await QuickMessage.findByPk(id);
// Verifique se a mensagem foi encontrada
if (!quickmessage) {
throw new AppError("Arquivo não encontrado", 404);
}
// Aplique a mesma lógica de renomeação para gerar o nome correto do arquivo
let filename = quickmessage.mediaName;
// Se o filename já tiver sido alterado (adicionando timestamp), remova esse prefixo
const timestampRegex = /^\d+_/;
if (timestampRegex.test(filename)) {
// Remover o timestamp do começo do nome do arquivo
filename = filename.replace(timestampRegex, '');
}
const filePath = path.resolve(
"public",
`company${companyId}`,
"quick",
filename
);
const fileExists = fs.existsSync(filePath);
if (fileExists) {
fs.unlinkSync(filePath); // Exclui o arquivo
}
// Atualiza os dados da mensagem no banco
await quickmessage.update({
mediaPath: null,
mediaName: null
});
return res.send({ mensagem: "Arquivo Excluído" });
} catch (err: any) {
throw new AppError(err.message);
}
};

View File

@ -0,0 +1,105 @@
import { Request, Response } from 'express';
import { QueryTypes } from 'sequelize';
import sequelize from '../database';
type RequestQueryProps = {
companyId: string;
initialDate: string;
finalDate: string;
};
export const appointmentsAtendent = async (
req: Request,
res: Response,
): Promise<Response> => {
const { companyId, initialDate, finalDate } = req.query as RequestQueryProps;
const resultAppointmentsByAttendents = await sequelize.query(
`
SELECT
u."name" as user_name
,COUNT(t.*) as total_tickets
FROM "Users" u
LEFT JOIN "TicketTraking" tt ON tt."userId" = u.id
LEFT JOIN "Tickets" t ON t.id = tt."ticketId" AND t."createdAt" BETWEEN '${initialDate}' AND '${finalDate}'
where u."companyId" = ${companyId}
GROUP BY u."name"
ORDER BY total_tickets ASC
`,
{ type: QueryTypes.SELECT },
);
const resultTicketsByQueues = await sequelize.query(
`
SELECT
q."name"
,COUNT(DISTINCT t.id) as total_tickets
FROM "Queues" q
LEFT JOIN "Messages" m ON m."queueId" = q.id
LEFt JOIN "Tickets" t ON t.id = m."ticketId" AND t."createdAt" BETWEEN '${initialDate}' AND '${finalDate}'
WHERE q."companyId" = ${companyId}
GROUP BY q."name"
ORDER BY total_tickets ASC
`,
{ type: QueryTypes.SELECT },
);
return res.json({
appointmentsByAttendents: resultAppointmentsByAttendents,
ticketsByQueues: resultTicketsByQueues,
});
};
export const rushHour = async (
req: Request,
res: Response,
): Promise<Response> => {
const { companyId, initialDate, finalDate } = req.query as RequestQueryProps;
const resultAppointmentsByHours = await sequelize.query(
`
SELECT
extract (hour from m."createdAt") AS message_hour,
COUNT(m.id) AS message_count
FROM "Messages" m
LEFT JOIN "Tickets" t ON t.id = m."ticketId"
WHERE t."companyId" = ${companyId}
AND m."createdAt" BETWEEN '${initialDate}' AND '${finalDate}'
GROUP BY
extract (hour from m."createdAt")
ORDER BY
extract (hour from m."createdAt")
`,
{ type: QueryTypes.SELECT },
);
return res.json(resultAppointmentsByHours);
};
export const departamentRatings = async (
req: Request,
res: Response,
): Promise<Response> => {
const { companyId, initialDate, finalDate } = req.query as RequestQueryProps;
const resultDepartamentRating = await sequelize.query(
`
SELECT
m."ticketId"
,q."name"
,round(avg(ur.rate), 2) AS total_rate
FROM "Messages" m
LEFT JOIN "Tickets" t ON t.id = m."ticketId"
LEFT JOIN "UserRatings" ur ON ur."ticketId" = t.id
LEFT JOIN "Queues" q ON q.id = m."queueId"
WHERE m."queueId" IS NOT NULL
AND m."companyId" = ${companyId}
AND ur."createdAt" BETWEEN '${initialDate}' AND '${finalDate}'
GROUP BY m."ticketId", q."name"
`,
{ type: QueryTypes.SELECT },
);
return res.json(resultDepartamentRating);
};

View File

@ -0,0 +1,154 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import AppError from "../errors/AppError";
import CreateService from "../services/ScheduleServices/CreateService";
import ListService from "../services/ScheduleServices/ListService";
import UpdateService from "../services/ScheduleServices/UpdateService";
import ShowService from "../services/ScheduleServices/ShowService";
import DeleteService from "../services/ScheduleServices/DeleteService";
import Schedule from "../models/Schedule";
import path from "path";
import fs from "fs";
import { head } from "lodash";
type IndexQuery = {
searchParam?: string;
contactId?: number | string;
userId?: number | string;
pageNumber?: string | number;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { contactId, userId, pageNumber, searchParam } = req.query as IndexQuery;
const { companyId } = req.user;
const { schedules, count, hasMore } = await ListService({
searchParam,
contactId,
userId,
pageNumber,
companyId
});
return res.json({ schedules, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const {
body,
sendAt,
contactId,
userId
} = req.body;
const { companyId } = req.user;
const schedule = await CreateService({
body,
sendAt,
contactId,
companyId,
userId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit("schedule", {
action: "create",
schedule
});
return res.status(200).json(schedule);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { scheduleId } = req.params;
const { companyId } = req.user;
const schedule = await ShowService(scheduleId, companyId);
return res.status(200).json(schedule);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
if (req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
const { scheduleId } = req.params;
const scheduleData = req.body;
const { companyId } = req.user;
const schedule = await UpdateService({ scheduleData, id: scheduleId, companyId });
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit("schedule", {
action: "update",
schedule
});
return res.status(200).json(schedule);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { scheduleId } = req.params;
const { companyId } = req.user;
await DeleteService(scheduleId, companyId);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit("schedule", {
action: "delete",
scheduleId
});
return res.status(200).json({ message: "Schedule deleted" });
};
export const mediaUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
const files = req.files as Express.Multer.File[];
const file = head(files);
try {
const schedule = await Schedule.findByPk(id);
schedule.mediaPath = file.filename;
schedule.mediaName = file.originalname;
await schedule.save();
return res.send({ mensagem: "Arquivo Anexado" });
} catch (err: any) {
throw new AppError(err.message);
}
};
export const deleteMedia = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
try {
const schedule = await Schedule.findByPk(id);
const filePath = path.resolve("public", schedule.mediaPath);
const fileExists = fs.existsSync(filePath);
if (fileExists) {
fs.unlinkSync(filePath);
}
schedule.mediaPath = null;
schedule.mediaName = null;
await schedule.save();
return res.send({ mensagem: "Arquivo Excluído" });
} catch (err: any) {
throw new AppError(err.message);
}
};

View File

@ -0,0 +1,80 @@
import { Request, Response } from "express";
import AppError from "../errors/AppError";
import { getIO } from "../libs/socket";
import AuthUserService from "../services/UserServices/AuthUserService";
import { SendRefreshToken } from "../helpers/SendRefreshToken";
import { RefreshTokenService } from "../services/AuthServices/RefreshTokenService";
import FindUserFromToken from "../services/AuthServices/FindUserFromToken";
import User from "../models/User";
export const store = async (req: Request, res: Response): Promise<Response> => {
const { email, password } = req.body;
const { token, serializedUser, refreshToken } = await AuthUserService({
email,
password
});
SendRefreshToken(res, refreshToken);
const io = getIO();
io.to(`user-${serializedUser.id}`).emit(`company-${serializedUser.companyId}-auth`, {
action: "update",
user: {
id: serializedUser.id,
email: serializedUser.email,
companyId: serializedUser.companyId
}
});
return res.status(200).json({
token,
user: serializedUser
});
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const token: string = req.cookies.jrt;
if (!token) {
throw new AppError("ERR_SESSION_EXPIRED", 401);
}
const { user, newToken, refreshToken } = await RefreshTokenService(
res,
token
);
SendRefreshToken(res, refreshToken);
return res.json({ token: newToken, user });
};
export const me = async (req: Request, res: Response): Promise<Response> => {
const token: string = req.cookies.jrt;
const user = await FindUserFromToken(token);
const { id, profile, super: superAdmin } = user;
if (!token) {
throw new AppError("ERR_SESSION_EXPIRED", 401);
}
return res.json({ id, profile, super: superAdmin });
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.user;
const user = await User.findByPk(id);
await user.update({ online: false });
res.clearCookie("jrt");
return res.send();
};

View File

@ -0,0 +1,158 @@
import { Request, Response } from "express";
import authConfig from "../config/auth";
import * as Yup from "yup";
import { getIO } from "../libs/socket";
import AppError from "../errors/AppError";
import { head } from "lodash";
import fs from "fs";
import path from "path";
import User from "../models/User";
import Company from "../models/Company";
import UpdateSettingService from "../services/SettingServices/UpdateSettingService";
import ListSettingsService from "../services/SettingServices/ListSettingsService";
import ShowSettingsService from "../services/SettingServices/ShowSettingsService";
export const index = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
//if (req.user.profile !== "admin") {
//throw new AppError("ERR_NO_PERMISSION", 403);
//}
const settings = await ListSettingsService({ companyId });
return res.status(200).json(settings);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
if (req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
const { settingKey: key } = req.params;
const { value } = req.body;
const { companyId } = req.user;
const setting = await UpdateSettingService({
key,
value,
companyId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-settings`, {
action: "update",
setting
});
return res.status(200).json(setting);
};
export const show = async (
req: Request,
res: Response
): Promise<Response> => {
//const { companyId } = req.user;
const companyId = 1;
const { settingKey } = req.params;
const retornoData = await ShowSettingsService({ settingKey, companyId });
return res.status(200).json(retornoData);
};
export const mediaUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { body } = req.body;
const { companyId } = req.user;
const userId = req.user.id;
const requestUser = await User.findByPk(userId);
if (requestUser.super === false) {
throw new AppError("você nao tem permissão para esta ação!");
}
if (req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
if (companyId !== 1) {
throw new AppError("ERR_NO_PERMISSION", 403);
}
const files = req.files as Express.Multer.File[];
const file = head(files);
console.log(file);
return res.send({ mensagem: "Arquivo Anexado" });
};
export const certUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { body } = req.body;
const { companyId } = req.user;
const userId = req.user.id;
const requestUser = await User.findByPk(userId);
if (requestUser.super === false) {
throw new AppError("você nao tem permissão para esta ação!");
}
if (req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
if (companyId !== 1) {
throw new AppError("ERR_NO_PERMISSION", 403);
}
const files = req.files as Express.Multer.File[];
const file = head(files);
console.log(file);
return res.send({ mensagem: "Arquivo Anexado" });
};
export const docUpload = async (
req: Request,
res: Response
): Promise<Response> => {
const { body } = req.body;
const { companyId } = req.user;
const userId = req.user.id;
const requestUser = await User.findByPk(userId);
if (requestUser.super === false) {
throw new AppError("você nao tem permissão para esta ação!");
}
if (req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
if (companyId !== 1) {
throw new AppError("ERR_NO_PERMISSION", 403);
}
const files = req.files as Express.Multer.File[];
const file = head(files);
console.log(file);
return res.send({ mensagem: "Arquivo Anexado" });
};

View File

@ -0,0 +1,199 @@
import { Request, Response } from "express";
import express from "express";
import * as Yup from "yup";
import Gerencianet from "gn-api-sdk-typescript";
import AppError from "../errors/AppError";
import options from "../config/Gn";
import Company from "../models/Company";
import Invoices from "../models/Invoices";
import Subscriptions from "../models/Subscriptions";
import { getIO } from "../libs/socket";
import UpdateUserService from "../services/UserServices/UpdateUserService";
const app = express();
export const index = async (req: Request, res: Response): Promise<Response> => {
const gerencianet = Gerencianet(options);
return res.json(gerencianet.getSubscriptions());
};
export const createSubscription = async (
req: Request,
res: Response
): Promise<Response> => {
const gerencianet = Gerencianet(options);
const { companyId } = req.user;
const schema = Yup.object().shape({
price: Yup.string().required(),
users: Yup.string().required(),
connections: Yup.string().required()
});
if (!(await schema.isValid(req.body))) {
throw new AppError("Validation fails", 400);
}
const {
firstName,
price,
users,
connections,
address2,
city,
state,
zipcode,
country,
plan,
invoiceId
} = req.body;
const body = {
calendario: {
expiracao: 3600
},
valor: {
original: price.toLocaleString("pt-br", { minimumFractionDigits: 2 }).replace(",", ".")
},
chave: process.env.GERENCIANET_PIX_KEY,
solicitacaoPagador: `#Fatura:${invoiceId}`
};
try {
const pix = await gerencianet.pixCreateImmediateCharge(null, body);
const qrcode = await gerencianet.pixGenerateQRCode({
id: pix.loc.id
});
const updateCompany = await Company.findOne();
if (!updateCompany) {
throw new AppError("Company not found", 404);
}
/* await Subscriptions.create({
companyId,
isActive: false,
userPriceCents: users,
whatsPriceCents: connections,
lastInvoiceUrl: pix.location,
lastPlanChange: new Date(),
providerSubscriptionId: pix.loc.id,
expiresAt: new Date()
}); */
/* const { id } = req.user;
const userData = {};
const userId = id;
const requestUserId = parseInt(id);
const user = await UpdateUserService({ userData, userId, companyId, requestUserId }); */
/* const io = getIO();
io.emit("user", {
action: "update",
user
}); */
return res.json({
...pix,
qrcode,
});
} catch (error) {
throw new AppError("Validation fails", 400);
}
};
export const createWebhook = async (
req: Request,
res: Response
): Promise<Response> => {
const schema = Yup.object().shape({
chave: Yup.string().required(),
url: Yup.string().required()
});
if (!(await schema.isValid(req.body))) {
throw new AppError("Validation fails", 400);
}
const { chave, url } = req.body;
const body = {
webhookUrl: url
};
const params = {
chave
};
try {
const gerencianet = Gerencianet(options);
const create = await gerencianet.pixConfigWebhook(params, body);
return res.json(create);
} catch (error) {
console.log(error);
}
};
export const webhook = async (
req: Request,
res: Response
): Promise<Response> => {
const { type } = req.params;
const { evento } = req.body;
if (evento === "teste_webhook") {
return res.json({ ok: true });
}
if (req.body.pix) {
const gerencianet = Gerencianet(options);
req.body.pix.forEach(async (pix: any) => {
const detahe = await gerencianet.pixDetailCharge({
txid: pix.txid
});
if (detahe.status === "CONCLUIDA") {
const { solicitacaoPagador } = detahe;
const invoiceID = solicitacaoPagador.replace("#Fatura:", "");
const invoices = await Invoices.findByPk(invoiceID);
const companyId =invoices.companyId;
const company = await Company.findByPk(companyId);
const expiresAt = new Date(company.dueDate);
expiresAt.setDate(expiresAt.getDate() + 30);
const date = expiresAt.toISOString().split("T")[0];
if (company) {
await company.update({
dueDate: date
});
const invoi = await invoices.update({
id: invoiceID,
status: 'paid'
});
await company.reload();
const io = getIO();
const companyUpdate = await Company.findOne({
where: {
id: companyId
}
});
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-payment`, {
action: detahe.status,
company: companyUpdate
});
}
}
});
}
return res.json({ ok: true });
};

View File

@ -0,0 +1,128 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import AppError from "../errors/AppError";
import CreateService from "../services/TagServices/CreateService";
import ListService from "../services/TagServices/ListService";
import UpdateService from "../services/TagServices/UpdateService";
import ShowService from "../services/TagServices/ShowService";
import DeleteService from "../services/TagServices/DeleteService";
import SimpleListService from "../services/TagServices/SimpleListService";
import SyncTagService from "../services/TagServices/SyncTagsService";
import KanbanListService from "../services/TagServices/KanbanListService";
type IndexQuery = {
searchParam?: string;
pageNumber?: string | number;
kanban?: number;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { pageNumber, searchParam } = req.query as IndexQuery;
const { companyId } = req.user;
const { tags, count, hasMore } = await ListService({
searchParam,
pageNumber,
companyId
});
return res.json({ tags, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { name, color, kanban } = req.body;
const { companyId } = req.user;
const tag = await CreateService({
name,
color,
companyId,
kanban
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit("tag", {
action: "create",
tag
});
return res.status(200).json(tag);
};
export const kanban = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const tags = await KanbanListService({ companyId });
return res.json({lista:tags});
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { tagId } = req.params;
const tag = await ShowService(tagId);
return res.status(200).json(tag);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
if (req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
const { tagId } = req.params;
const tagData = req.body;
const tag = await UpdateService({ tagData, id: tagId });
const io = getIO();
io.to(`company-${req.user.companyId}-mainchannel`).emit("tag", {
action: "update",
tag
});
return res.status(200).json(tag);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { tagId } = req.params;
await DeleteService(tagId);
const io = getIO();
io.to(`company-${req.user.companyId}-mainchannel`).emit("tag", {
action: "delete",
tagId
});
return res.status(200).json({ message: "Tag deleted" });
};
export const list = async (req: Request, res: Response): Promise<Response> => {
const { searchParam } = req.query as IndexQuery;
const { companyId } = req.user;
const tags = await SimpleListService({ searchParam, companyId });
return res.json(tags);
};
export const syncTags = async (
req: Request,
res: Response
): Promise<Response> => {
const data = req.body;
const { companyId } = req.user;
const tags = await SyncTagService({ ...data, companyId });
return res.json(tags);
};

View File

@ -0,0 +1,378 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import Ticket from "../models/Ticket";
import CreateTicketService from "../services/TicketServices/CreateTicketService";
import DeleteTicketService from "../services/TicketServices/DeleteTicketService";
import ListTicketsService from "../services/TicketServices/ListTicketsService";
import ShowTicketUUIDService from "../services/TicketServices/ShowTicketFromUUIDService";
import ShowTicketService from "../services/TicketServices/ShowTicketService";
import ListTicketsServiceReport from "../services/TicketServices/ListTicketsServiceReport";
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
import ListTicketsServiceKanban from "../services/TicketServices/ListTicketsServiceKanban";
type IndexQuery = {
searchParam: string;
pageNumber: string;
status: string;
date: string;
updatedAt?: string;
showAll: string;
withUnreadMessages: string;
queueIds: string;
tags: string;
users: string;
};
interface TicketData {
contactId: number;
status: string;
queueId: number;
userId: number;
whatsappId: string;
useIntegration: boolean;
promptId: number;
integrationId: number;
}
type IndexQueryReport = {
searchParam: string;
contactId: string;
whatsappId: string;
dateFrom: string;
dateTo: string;
status: string;
//lastMessage: string;
queueIds: string;
tags: string;
users: string;
page: string;
pageSize: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
console.log("FUNÇÃO INDEX EXECUTADA");
const {
pageNumber,
status,
date,
updatedAt,
searchParam,
showAll,
queueIds: queueIdsStringified,
tags: tagIdsStringified,
users: userIdsStringified,
withUnreadMessages
} = req.query as IndexQuery;
const userId = req.user.id;
const { companyId } = req.user;
let queueIds: number[] = [];
let tagsIds: number[] = [];
let usersIds: number[] = [];
if (queueIdsStringified) {
queueIds = JSON.parse(queueIdsStringified);
}
if (tagIdsStringified) {
tagsIds = JSON.parse(tagIdsStringified);
}
if (userIdsStringified) {
usersIds = JSON.parse(userIdsStringified);
}
const { tickets, count, hasMore } = await ListTicketsService({
searchParam,
tags: tagsIds,
users: usersIds,
pageNumber,
status,
date,
updatedAt,
showAll,
userId,
queueIds,
withUnreadMessages,
companyId,
});
return res.status(200).json({ tickets, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
console.log("FUNÇÃO STORE EXECUTADA");
const { contactId, status, userId, queueId, whatsappId }: TicketData = req.body;
const { companyId } = req.user;
const ticket = await CreateTicketService({
contactId,
status,
userId,
companyId,
queueId,
whatsappId
});
const io = getIO();
io.to(ticket.status).emit(`company-${companyId}-ticket`, {
action: "update",
ticket
});
return res.status(200).json(ticket);
};
export const kanban = async (req: Request, res: Response): Promise<Response> => {
console.log("FUNÇÃO KANBAN EXECUTADA");
const {
pageNumber,
status,
date,
updatedAt,
searchParam,
showAll,
queueIds: queueIdsStringified,
tags: tagIdsStringified,
users: userIdsStringified,
withUnreadMessages
} = req.query as IndexQuery;
const userId = req.user.id;
const { companyId } = req.user;
let queueIds: number[] = [];
let tagsIds: number[] = [];
let usersIds: number[] = [];
if (queueIdsStringified) {
queueIds = JSON.parse(queueIdsStringified);
}
if (tagIdsStringified) {
tagsIds = JSON.parse(tagIdsStringified);
}
if (userIdsStringified) {
usersIds = JSON.parse(userIdsStringified);
}
const { tickets, count, hasMore } = await ListTicketsServiceKanban({
searchParam,
tags: tagsIds,
users: usersIds,
pageNumber,
status,
date,
updatedAt,
showAll,
userId,
queueIds,
withUnreadMessages,
companyId
});
return res.status(200).json({ tickets, count, hasMore });
};
export const show = async (req: Request, res: Response): Promise<Response> => {
console.log("FUNÇÃO SHOW EXECUTADA");
const { ticketId } = req.params;
const { companyId } = req.user;
console.log("VALOR DE ticketId NA FUNÇÃO SHOW:", ticketId); // Novo log para ver o valor
if (!ticketId || ticketId === "undefined" || isNaN(+ticketId)) {
console.log("ERRO: ticketId inválido detectado na função SHOW:", ticketId);
return res.status(400).json({ error: "Ticket ID inválido" });
}
const contact = await ShowTicketService(ticketId, companyId);
return res.status(200).json(contact);
};
export const showFromUUID = async (
req: Request,
res: Response
): Promise<Response> => {
const { uuid } = req.params;
const ticket: Ticket = await ShowTicketUUIDService(uuid);
return res.status(200).json(ticket);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
console.log("FUNÇÃO UPDATE EXECUTADA");
const { ticketId } = req.params;
const ticketData: TicketData = req.body;
const { companyId } = req.user;
console.log("VALOR DE ticketId NA FUNÇÃO UPDATE:", ticketId); // Novo log
console.log("DADOS ENVIADOS NA FUNÇÃO UPDATE:", ticketData); // Novo log
const { ticket } = await UpdateTicketService({
ticketData,
ticketId,
companyId
});
console.log("TICKET RETORNADO POR UPDATE:", ticket); // Novo log
return res.status(200).json(ticket);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
console.log("FUNÇÃO REMOVE EXECUTADA");
const { ticketId } = req.params;
const { companyId } = req.user;
await ShowTicketService(ticketId, companyId);
const ticket = await DeleteTicketService(ticketId);
const io = getIO();
io.to(ticketId)
.to(`company-${companyId}-${ticket.status}`)
.to(`company-${companyId}-notification`)
.to(`queue-${ticket.queueId}-${ticket.status}`)
.to(`queue-${ticket.queueId}-notification`)
.emit(`company-${companyId}-ticket`, {
action: "delete",
ticketId: +ticketId
});
return res.status(200).json({ message: "ticket deleted" });
};
export const report = async (req: Request, res: Response): Promise<Response> => {
console.log("FUNÇÃO REPORT EXECUTADA");
const {
searchParam,
contactId,
whatsappId: whatsappIdsStringified,
dateFrom,
dateTo,
status: statusStringified,
//lastMessage,
queueIds: queueIdsStringified,
tags: tagIdsStringified,
users: userIdsStringified,
page: pageNumber,
pageSize
} = req.query as IndexQueryReport;
const userId = req.user.id;
const { companyId } = req.user;
let queueIds: number[] = [];
let whatsappIds: string[] = [];
let tagsIds: number[] = [];
let usersIds: number[] = [];
let statusIds: string[] = [];
if (statusStringified) {
statusIds = JSON.parse(statusStringified);
}
if (whatsappIdsStringified) {
whatsappIds = JSON.parse(whatsappIdsStringified);
}
if (queueIdsStringified) {
queueIds = JSON.parse(queueIdsStringified);
}
if (tagIdsStringified) {
tagsIds = JSON.parse(tagIdsStringified);
}
if (userIdsStringified) {
usersIds = JSON.parse(userIdsStringified);
}
const { tickets, totalTickets } = await ListTicketsServiceReport(
companyId,
{
searchParam,
queueIds,
tags: tagsIds,
users: usersIds,
status: statusIds,
dateFrom,
dateTo,
userId,
contactId,
whatsappId: whatsappIds
},
+pageNumber,
+pageSize
);
return res.status(200).json({ tickets, totalTickets });
};
export const closeAll = async (req: Request, res: Response): Promise<Response> => {
console.log("FUNÇÃO CLOSEALL EXECUTADA");
const { companyId } = req.user;
const { status }: TicketData = req.body;
const io = getIO();
const { rows: tickets } = await Ticket.findAndCountAll({
where: { companyId: companyId, status: status },
order: [["updatedAt", "DESC"]]
});
tickets.forEach(async ticket => {
await ticket.update({
status: "closed",
useIntegration: false,
promptId: null,
integrationId: null,
unreadMessages: 0
})
const io = getIO();
io.to(`${ticket.id}`)
.to(`company-${companyId}-${ticket.status}`)
.to(`company-${companyId}-notification`)
.to(`queue-${ticket.queueId}-${ticket.status}`)
.to(`queue-${ticket.queueId}-notification`)
.emit(`company-${companyId}-ticket`, {
action: "delete",
ticketId: ticket.id
});
});
return res.status(200).json();
};

View File

@ -0,0 +1,138 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import AppError from "../errors/AppError";
import TicketNote from "../models/TicketNote";
import ListTicketNotesService from "../services/TicketNoteService/ListTicketNotesService";
import CreateTicketNoteService from "../services/TicketNoteService/CreateTicketNoteService";
import UpdateTicketNoteService from "../services/TicketNoteService/UpdateTicketNoteService";
import ShowTicketNoteService from "../services/TicketNoteService/ShowTicketNoteService";
import FindAllTicketNotesService from "../services/TicketNoteService/FindAllTicketNotesService";
import DeleteTicketNoteService from "../services/TicketNoteService/DeleteTicketNoteService";
import FindNotesByContactIdAndTicketId from "../services/TicketNoteService/FindNotesByContactIdAndTicketId";
type IndexQuery = {
searchParam: string;
pageNumber: string;
};
type StoreTicketNoteData = {
note: string;
userId: number;
contactId: number | 0;
ticketId: number | 0;
id?: number | string;
};
type UpdateTicketNoteData = {
note: string;
id?: number | string;
userId?: number | 0;
contactId?: number | 0;
ticketId?: number | 0;
};
type QueryFilteredNotes = {
contactId: number | string;
ticketId: number | string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { ticketNotes, count, hasMore } = await ListTicketNotesService({
searchParam,
pageNumber
});
return res.json({ ticketNotes, count, hasMore });
};
export const list = async (req: Request, res: Response): Promise<Response> => {
const ticketNotes: TicketNote[] = await FindAllTicketNotesService();
return res.status(200).json(ticketNotes);
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const newTicketNote: StoreTicketNoteData = req.body;
const { id: userId } = req.user;
const schema = Yup.object().shape({
note: Yup.string().required()
});
try {
await schema.validate(newTicketNote);
} catch (err) {
throw new AppError(err.message);
}
const ticketNote = await CreateTicketNoteService({
...newTicketNote,
userId
});
return res.status(200).json(ticketNote);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { id } = req.params;
const ticketNote = await ShowTicketNoteService(id);
return res.status(200).json(ticketNote);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const ticketNote: UpdateTicketNoteData = req.body;
const schema = Yup.object().shape({
note: Yup.string()
});
try {
await schema.validate(ticketNote);
} catch (err) {
throw new AppError(err.message);
}
const recordUpdated = await UpdateTicketNoteService(ticketNote);
return res.status(200).json(recordUpdated);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { id } = req.params;
if (req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
await DeleteTicketNoteService(id);
return res.status(200).json({ message: "Observação removida" });
};
export const findFilteredList = async (
req: Request,
res: Response
): Promise<Response> => {
try {
const { contactId, ticketId } = req.query as QueryFilteredNotes;
const notes: TicketNote[] = await FindNotesByContactIdAndTicketId({
contactId,
ticketId
});
return res.status(200).json(notes);
} catch (e) {
return res.status(500).json({ message: e });
}
};

View File

@ -0,0 +1,57 @@
import { Request, Response } from "express";
import AppError from "../errors/AppError";
import TicketTag from '../models/TicketTag';
import Tag from '../models/Tag'
export const store = async (req: Request, res: Response): Promise<Response> => {
const { ticketId, tagId } = req.params;
try {
const ticketTag = await TicketTag.create({ ticketId, tagId });
return res.status(201).json(ticketTag);
} catch (error) {
return res.status(500).json({ error: 'Failed to store ticket tag.' });
}
};
/*
export const remove = async (req: Request, res: Response): Promise<Response> => {
const { ticketId } = req.params;
try {
await TicketTag.destroy({ where: { ticketId } });
return res.status(200).json({ message: 'Ticket tags removed successfully.' });
} catch (error) {
return res.status(500).json({ error: 'Failed to remove ticket tags.' });
}
};
*/
export const remove = async (req: Request, res: Response): Promise<Response> => {
const { ticketId } = req.params;
try {
// Retrieve tagIds associated with the provided ticketId from TicketTags
const ticketTags = await TicketTag.findAll({ where: { ticketId } });
const tagIds = ticketTags.map((ticketTag) => ticketTag.tagId);
// Find the tagIds with kanban = 1 in the Tags table
const tagsWithKanbanOne = await Tag.findAll({
where: {
id: tagIds,
kanban: 1,
},
});
// Remove the tagIds with kanban = 1 from TicketTags
const tagIdsWithKanbanOne = tagsWithKanbanOne.map((tag) => tag.id);
if (tagIdsWithKanbanOne)
await TicketTag.destroy({ where: { ticketId, tagId: tagIdsWithKanbanOne } });
return res.status(200).json({ message: 'Ticket tags removed successfully.' });
} catch (error) {
return res.status(500).json({ error: 'Failed to remove ticket tags.' });
}
};

View File

@ -0,0 +1,155 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import CheckSettingsHelper from "../helpers/CheckSettings";
import AppError from "../errors/AppError";
import CreateUserService from "../services/UserServices/CreateUserService";
import ListUsersService from "../services/UserServices/ListUsersService";
import UpdateUserService from "../services/UserServices/UpdateUserService";
import ShowUserService from "../services/UserServices/ShowUserService";
import DeleteUserService from "../services/UserServices/DeleteUserService";
import SimpleListService from "../services/UserServices/SimpleListService";
import User from "../models/User";
type IndexQuery = {
searchParam: string;
pageNumber: string;
};
type ListQueryParams = {
companyId: string;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
const { searchParam, pageNumber } = req.query as IndexQuery;
const { companyId, profile } = req.user;
const { users, count, hasMore } = await ListUsersService({
searchParam,
pageNumber,
companyId,
profile
});
return res.json({ users, count, hasMore });
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const {
email,
password,
name,
profile,
companyId: bodyCompanyId,
queueIds,
whatsappId,
allTicket
} = req.body;
const whatsappNumber = typeof req.body.whatsappNumber === "string" ? req.body.whatsappNumber.trim() : null;
let userCompanyId: number | null = null;
let requestUser: User | null = null;
if (req.user !== undefined) {
const { companyId: cId } = req.user;
userCompanyId = cId;
requestUser = await User.findByPk(req.user.id);
}
const newUserCompanyId = bodyCompanyId || userCompanyId;
if (req.url === "/signup") {
if (await CheckSettingsHelper("userCreation") === "disabled") {
throw new AppError("ERR_USER_CREATION_DISABLED", 403);
}
} else if (req.user?.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
} else if (newUserCompanyId !== req.user?.companyId && !requestUser?.super) {
throw new AppError("ERR_NO_SUPER", 403);
}
const user = await CreateUserService({
email,
password,
name,
profile,
companyId: newUserCompanyId,
queueIds,
whatsappId,
allTicket,
whatsappNumber
});
const io = getIO();
io.to(`company-${userCompanyId}-mainchannel`).emit(`company-${userCompanyId}-user`, {
action: "create",
user
});
return res.status(200).json(user);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { userId } = req.params;
const user = await ShowUserService(userId);
return res.status(200).json(user);
};
export const update = async (req: Request, res: Response): Promise<Response> => {
const { id: requestUserId, companyId } = req.user;
const { userId } = req.params;
const userData = req.body;
if (typeof userData.whatsappNumber !== "string") {
userData.whatsappNumber = null;
} else {
userData.whatsappNumber = userData.whatsappNumber.trim();
}
const user = await UpdateUserService({
userData,
userId,
companyId,
requestUserId: +requestUserId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-user`, {
action: "update",
user
});
return res.status(200).json(user);
};
export const remove = async (req: Request, res: Response): Promise<Response> => {
const { userId } = req.params;
const { companyId } = req.user;
if (req.user.profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
await DeleteUserService(userId, companyId);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-user`, {
action: "delete",
userId
});
return res.status(200).json({ message: "User deleted" });
};
export const list = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.query;
const { companyId: userCompanyId } = req.user;
const users = await SimpleListService({
companyId: companyId ? +companyId : userCompanyId
});
return res.status(200).json(users);
};

View File

@ -0,0 +1,7 @@
import { Request, Response } from "express";
export const index = async (req: Request, res: Response): Promise<Response> => {
return res.status(200).json({
version: "10.12.0"
});
};

View File

@ -0,0 +1,28 @@
import { Request, Response } from "express";
import Whatsapp from "../models/Whatsapp";
import HubMessageListener from "../services/HubServices/HubMessageListener";
export const listen = async (
req: Request,
res: Response
): Promise<Response> => {
console.log("Webhook received");
const medias = req.files as Express.Multer.File[];
const { channelId } = req.params;
const connection = await Whatsapp.findOne({
where: { qrcode: channelId }
});
if (!connection) {
return res.status(404).json({ message: "Whatsapp channel not found" });
}
try {
await HubMessageListener(req.body, connection, medias);
return res.status(200).json({ message: "Webhook received" });
} catch (error) {
return res.status(400).json({ message: error });
}
};

View File

@ -0,0 +1,185 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import { removeWbot, restartWbot } from "../libs/wbot";
import { StartWhatsAppSession } from "../services/WbotServices/StartWhatsAppSession";
import CreateWhatsAppService from "../services/WhatsappService/CreateWhatsAppService";
import DeleteWhatsAppService from "../services/WhatsappService/DeleteWhatsAppService";
import ListWhatsAppsService from "../services/WhatsappService/ListWhatsAppsService";
import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService";
import UpdateWhatsAppService from "../services/WhatsappService/UpdateWhatsAppService";
import AppError from "../errors/AppError";
interface WhatsappData {
name: string;
queueIds: number[];
companyId: number;
greetingMessage?: string;
complationMessage?: string;
outOfHoursMessage?: string;
ratingMessage?: string;
status?: string;
isDefault?: boolean;
token?: string;
//sendIdQueue?: number;
//timeSendQueue?: number;
transferQueueId?: number;
timeToTransfer?: number;
promptId?: number;
maxUseBotQueues?: number;
timeUseBotQueues?: number;
expiresTicket?: number;
expiresInactiveMessage?: string;
}
interface QueryParams {
session?: number | string;
}
export const index = async (req: Request, res: Response): Promise<Response> => {
const { companyId } = req.user;
const { session } = req.query as QueryParams;
const whatsapps = await ListWhatsAppsService({ companyId, session });
return res.status(200).json(whatsapps);
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const {
name,
status,
isDefault,
greetingMessage,
complationMessage,
ratingMessage,
outOfHoursMessage,
queueIds,
token,
//timeSendQueue,
//sendIdQueue,
transferQueueId,
timeToTransfer,
promptId,
maxUseBotQueues,
timeUseBotQueues,
expiresTicket,
expiresInactiveMessage
}: WhatsappData = req.body;
const { companyId } = req.user;
const { whatsapp, oldDefaultWhatsapp } = await CreateWhatsAppService({
name,
status,
isDefault,
greetingMessage,
complationMessage,
ratingMessage,
outOfHoursMessage,
queueIds,
companyId,
token,
//timeSendQueue,
//sendIdQueue,
transferQueueId,
timeToTransfer,
promptId,
maxUseBotQueues,
timeUseBotQueues,
expiresTicket,
expiresInactiveMessage
});
StartWhatsAppSession(whatsapp, companyId);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-whatsapp`, {
action: "update",
whatsapp
});
if (oldDefaultWhatsapp) {
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-whatsapp`, {
action: "update",
whatsapp: oldDefaultWhatsapp
});
}
return res.status(200).json(whatsapp);
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { whatsappId } = req.params;
const { companyId } = req.user;
const { session } = req.query;
const whatsapp = await ShowWhatsAppService(whatsappId, companyId, session);
return res.status(200).json(whatsapp);
};
export const update = async (
req: Request,
res: Response
): Promise<Response> => {
const { whatsappId } = req.params;
const whatsappData = req.body;
const { companyId } = req.user;
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
whatsappData,
whatsappId,
companyId
});
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-whatsapp`, {
action: "update",
whatsapp
});
if (oldDefaultWhatsapp) {
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-whatsapp`, {
action: "update",
whatsapp: oldDefaultWhatsapp
});
}
return res.status(200).json(whatsapp);
};
export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
const { whatsappId } = req.params;
const { companyId } = req.user;
await ShowWhatsAppService(whatsappId, companyId);
await DeleteWhatsAppService(whatsappId);
removeWbot(+whatsappId);
const io = getIO();
io.to(`company-${companyId}-mainchannel`).emit(`company-${companyId}-whatsapp`, {
action: "delete",
whatsappId: +whatsappId
});
return res.status(200).json({ message: "Whatsapp deleted." });
};
export const restart = async (
req: Request,
res: Response
): Promise<Response> => {
const { companyId, profile } = req.user;
if (profile !== "admin") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
await restartWbot(companyId);
return res.status(200).json({ message: "Whatsapp restart." });
};

View File

@ -0,0 +1,44 @@
import { Request, Response } from "express";
import { getWbot } from "../libs/wbot";
import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService";
import { StartWhatsAppSession } from "../services/WbotServices/StartWhatsAppSession";
import UpdateWhatsAppService from "../services/WhatsappService/UpdateWhatsAppService";
const store = async (req: Request, res: Response): Promise<Response> => {
const { whatsappId } = req.params;
const { companyId } = req.user;
const whatsapp = await ShowWhatsAppService(whatsappId, companyId);
await StartWhatsAppSession(whatsapp, companyId);
return res.status(200).json({ message: "Starting session." });
};
const update = async (req: Request, res: Response): Promise<Response> => {
const { whatsappId } = req.params;
const { companyId } = req.user;
const whatsapp = await ShowWhatsAppService(whatsappId, companyId);
await whatsapp.update({ session: "" });
await StartWhatsAppSession(whatsapp, companyId);
return res.status(200).json({ message: "Starting session." });
};
const remove = async (req: Request, res: Response): Promise<Response> => {
const { whatsappId } = req.params;
const { companyId } = req.user;
const whatsapp = await ShowWhatsAppService(whatsappId, companyId);
if (whatsapp.session) {
await whatsapp.update({ status: "DISCONNECTED", session: "" });
const wbot = getWbot(whatsapp.id);
await wbot.logout();
}
return res.status(200).json({ message: "Session disconnected." });
};
export default { store, remove, update };

View File

@ -0,0 +1,93 @@
import { Sequelize } from "sequelize-typescript";
import User from "../models/User";
import Setting from "../models/Setting";
import Contact from "../models/Contact";
import Ticket from "../models/Ticket";
import Whatsapp from "../models/Whatsapp";
import ContactCustomField from "../models/ContactCustomField";
import Message from "../models/Message";
import Queue from "../models/Queue";
import WhatsappQueue from "../models/WhatsappQueue";
import UserQueue from "../models/UserQueue";
import Company from "../models/Company";
import Plan from "../models/Plan";
import TicketNote from "../models/TicketNote";
import QuickMessage from "../models/QuickMessage";
import Help from "../models/Help";
import TicketTraking from "../models/TicketTraking";
import UserRating from "../models/UserRating";
import QueueOption from "../models/QueueOption";
import Schedule from "../models/Schedule";
import Tag from "../models/Tag";
import TicketTag from "../models/TicketTag";
import ContactList from "../models/ContactList";
import ContactListItem from "../models/ContactListItem";
import Campaign from "../models/Campaign";
import CampaignSetting from "../models/CampaignSetting";
import Baileys from "../models/Baileys";
import CampaignShipping from "../models/CampaignShipping";
import Announcement from "../models/Announcement";
import Chat from "../models/Chat";
import ChatUser from "../models/ChatUser";
import ChatMessage from "../models/ChatMessage";
import Invoices from "../models/Invoices";
import Subscriptions from "../models/Subscriptions";
import BaileysChats from "../models/BaileysChats";
import Files from "../models/Files";
import FilesOptions from "../models/FilesOptions";
import Prompt from "../models/Prompt";
import QueueIntegrations from "../models/QueueIntegrations";
// Adicione a importação do modelo HubNotificaMe
import HubNotificaMe from "../models/HubNotificaMe";
// eslint-disable-next-line
const dbConfig = require("../config/database");
const sequelize = new Sequelize(dbConfig);
const models = [
Company,
User,
Contact,
Ticket,
Message,
Whatsapp,
ContactCustomField,
Setting,
Queue,
WhatsappQueue,
UserQueue,
Plan,
TicketNote,
QuickMessage,
Help,
TicketTraking,
UserRating,
QueueOption,
Schedule,
Tag,
TicketTag,
ContactList,
ContactListItem,
Campaign,
CampaignSetting,
Baileys,
CampaignShipping,
Announcement,
Chat,
ChatUser,
ChatMessage,
Invoices,
Subscriptions,
BaileysChats,
Files,
FilesOptions,
Prompt,
QueueIntegrations,
HubNotificaMe,
];
sequelize.addModels(models);
export default sequelize;

View File

@ -0,0 +1,10 @@
import { QueryInterface } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return Promise.all([
queryInterface.sequelize.query('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'),
]);
},
};

View File

@ -0,0 +1,39 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("Users", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
passwordHash: {
type: DataTypes.STRING,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("Users");
}
};

View File

@ -0,0 +1,45 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("Contacts", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
name: {
type: DataTypes.STRING,
allowNull: false
},
number: {
type: DataTypes.STRING,
allowNull: true
},
profilePicUrl: {
type: DataTypes.TEXT
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
},
messengerId: {
type: DataTypes.STRING,
allowNull: true
},
instagramId: {
type: DataTypes.STRING,
allowNull: true
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("Contacts");
}
};

View File

@ -0,0 +1,46 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("Tickets", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
status: {
type: DataTypes.STRING,
defaultValue: "pending",
allowNull: false
},
lastMessage: {
type: DataTypes.STRING
},
contactId: {
type: DataTypes.INTEGER,
references: { model: "Contacts", key: "id" },
onUpdate: "CASCADE",
onDelete: "CASCADE"
},
userId: {
type: DataTypes.INTEGER,
references: { model: "Users", key: "id" },
onUpdate: "CASCADE",
onDelete: "SET NULL"
},
createdAt: {
type: DataTypes.DATE(6),
allowNull: false
},
updatedAt: {
type: DataTypes.DATE(6),
allowNull: false
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("Tickets");
}
};

View File

@ -0,0 +1,58 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("Messages", {
id: {
type: DataTypes.STRING,
primaryKey: true,
allowNull: false
},
body: {
type: DataTypes.TEXT,
allowNull: false
},
ack: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
read: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
mediaType: {
type: DataTypes.STRING
},
mediaUrl: {
type: DataTypes.STRING
},
userId: {
type: DataTypes.INTEGER,
references: { model: "Users", key: "id" },
onUpdate: "CASCADE",
onDelete: "SET NULL"
},
ticketId: {
type: DataTypes.INTEGER,
references: { model: "Tickets", key: "id" },
onUpdate: "CASCADE",
onDelete: "CASCADE",
allowNull: false
},
createdAt: {
type: DataTypes.DATE(6),
allowNull: false
},
updatedAt: {
type: DataTypes.DATE(6),
allowNull: false
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("Messages");
}
};

View File

@ -0,0 +1,44 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("Whatsapps", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
session: {
type: DataTypes.TEXT
},
qrcode: {
type: DataTypes.TEXT
},
status: {
type: DataTypes.STRING
},
battery: {
type: DataTypes.STRING
},
plugged: {
type: DataTypes.BOOLEAN
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
},
type: {
type: DataTypes.STRING
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("Whatsapps");
}
};

View File

@ -0,0 +1,41 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("ContactCustomFields", {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
name: {
type: DataTypes.STRING,
allowNull: false
},
value: {
type: DataTypes.STRING,
allowNull: false
},
contactId: {
type: DataTypes.INTEGER,
references: { model: "Contacts", key: "id" },
onUpdate: "CASCADE",
onDelete: "CASCADE",
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("ContactCustomFields");
}
};

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Contacts", "email", {
type: DataTypes.STRING,
allowNull: false,
defaultValue: ""
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Contacts", "email");
}
};

View File

@ -0,0 +1,16 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Messages", "userId");
},
down: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Messages", "userId", {
type: DataTypes.INTEGER,
references: { model: "Users", key: "id" },
onUpdate: "CASCADE",
onDelete: "SET NULL"
});
}
};

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Messages", "fromMe", {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Messages", "fromMe");
}
};

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.changeColumn("Tickets", "lastMessage", {
type: DataTypes.TEXT
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.changeColumn("Tickets", "lastMessage", {
type: DataTypes.STRING
});
}
};

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Users", "profile", {
type: DataTypes.STRING,
allowNull: false,
defaultValue: "admin"
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Users", "profile");
}
};

View File

@ -0,0 +1,29 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("Settings", {
key: {
type: DataTypes.STRING,
primaryKey: true,
allowNull: false
},
value: {
type: DataTypes.TEXT,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("Settings");
}
};

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Whatsapps", "name", {
type: DataTypes.STRING,
allowNull: false,
unique: true
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Whatsapps", "name");
}
};

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Whatsapps", "default", {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Whatsapps", "default");
}
};

View File

@ -0,0 +1,16 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Tickets", "whatsappId", {
type: DataTypes.INTEGER,
references: { model: "Whatsapps", key: "id" },
onUpdate: "CASCADE",
onDelete: "SET NULL"
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Tickets", "whatsappId");
}
};

View File

@ -0,0 +1,11 @@
import { QueryInterface } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.renameColumn("Whatsapps", "default", "isDefault");
},
down: (queryInterface: QueryInterface) => {
return queryInterface.renameColumn("Whatsapps", "isDefault", "default");
}
};

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Messages", "isDeleted", {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Messages", "isDeleted");
}
};

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Users", "tokenVersion", {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Users", "tokenVersion");
}
};

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Tickets", "isGroup", {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Tickets", "isGroup");
}
};

Some files were not shown because too many files have changed in this diff Show More