Skip to content

Commit

Permalink
Add Personalização
Browse files Browse the repository at this point in the history
  • Loading branch information
rtenorioh committed Nov 15, 2024
1 parent b04fe8e commit 723639f
Show file tree
Hide file tree
Showing 35 changed files with 1,740 additions and 517 deletions.
42 changes: 38 additions & 4 deletions backend/api.rest
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
# PARA USAR PRECISA DA EXTENSÃO DO VS CODE "REST Client"

#Variaveis
@baseUrl = http://localhost:4000
@token = a3031d64-7423-4bfc-b43e-6b6f2ab24160
@baseUrl = http://localhost:8080
@token = 6175c0d0-acd5-4776-95a9-592c795da986
@token2 = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlByZXNzLVRpY2tldCIsInByb2ZpbGUiOiJhZG1pbiIsImlkIjoxLCJpYXQiOjE3MzEzNzIwNDksImV4cCI6MTczMTM3NTY0OX0.QwidYXoxONiHC7fsTF87IxLJ-nJ-aNrMFCK4habN2yQ

# (Enviar Mensagem) Teste da Rota POST /api/messages/send
### (Login) Teste da Rota POST /auth/login
POST {{baseUrl}}/auth/login
Content-Type: application/json

{
"email": "[email protected]",
"password": "admin"
}

### (Enviar Mensagem) Teste da Rota POST /api/messages/send
POST {{baseUrl}}/api/messages/send
Authorization: Bearer {{token}}
Content-Type: application/json
Expand All @@ -17,4 +27,28 @@ Content-Type: application/json
"whatsappId": "1"
}

###
### (Listar Personalizações) Teste da Rota GET /personalizations
GET {{baseUrl}}/personalizations
Content-Type: application/json

### (Criar ou Atualizar Personalização) Teste da Rota PUT /personalizations/:theme
PUT {{baseUrl}}/personalizations/light
Authorization: Bearer {{token2}}
Content-Type: application/json

{
"company": "Press Ticket",
"url": "https://pressticket.com.br",
"primaryColor": "#ffffff",
"secondaryColor": "#0000ff",
"backgroundDefault": "#ff00ff",
"backgroundPaper": "#00ff00",
"favico": "teste.ico",
"logo": null,
"logoTicket": null
}

### (Remover Personalização) Teste da Rota DELETE /personalizations/:theme
DELETE {{baseUrl}}/personalizations/light
Authorization: Bearer {{token2}}
Content-Type: application/json
4 changes: 3 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
"dependencies": {
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@sentry/node": "^5.29.2",
"@types/body-parser": "^1.19.5",
"@types/mime-types": "^2.1.4",
"@types/pino": "^6.3.4",
"axios": "^1.7.7",
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.3",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"date-fns": "^2.16.1",
Expand Down Expand Up @@ -103,4 +105,4 @@
"engines": {
"node": ">=18.0.0"
}
}
}
19 changes: 11 additions & 8 deletions backend/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import "./bootstrap";
import "reflect-metadata";
import "express-async-errors";
import express, { Request, Response, NextFunction } from "express";
import cors from "cors";
import cookieParser from "cookie-parser";
import * as Sentry from "@sentry/node";

import "./database";
import bodyParser from "body-parser";
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 uploadConfig from "./config/upload";
import "./database";
import AppError from "./errors/AppError";
import routes from "./routes";
import { logger } from "./utils/logger";
Expand All @@ -28,6 +28,9 @@ app.use(Sentry.Handlers.requestHandler());
app.use("/public", express.static(uploadConfig.directory));
app.use(routes);

app.use(bodyParser.json({ limit: "10mb" }));
app.use(bodyParser.urlencoded({ limit: "10mb", extended: true }));

app.use(Sentry.Handlers.errorHandler());

app.use(async (err: Error, req: Request, res: Response, _: NextFunction) => {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/config/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default {
secret: process.env.JWT_SECRET || "mysecret",
expiresIn: "15m",
expiresIn: "1h",
refreshSecret: process.env.JWT_REFRESH_SECRET || "myanothersecret",
refreshExpiresIn: "7d"
};
90 changes: 90 additions & 0 deletions backend/src/config/uploadConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Request } from "express";
import fs from "fs";
import multer, { FileFilterCallback } from "multer";
import path from "path";

const deleteIfExists = (filePath: string) => {
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
console.log(`Arquivo ${filePath} deletado com sucesso.`);
} else {
console.log(`Arquivo ${filePath} não encontrado para exclusão.`);
}
};

const storage = multer.diskStorage({
destination: (req, file, cb) => {
const dest = path.resolve(
__dirname,
"..",
"..",
"..",
"frontend",
"public",
"assets"
);
console.log(`Destino do upload: ${dest}`);
cb(null, dest);
},
filename: (req: Request, file, cb) => {
const { theme } = req.params;
console.log(`Tema recebido: ${theme}`);
let fileName = "";

if (theme === "light") {
if (file.fieldname === "favico") {
fileName = "favico.ico";
} else if (file.fieldname === "logo") {
fileName = "logo.jpg";
} else if (file.fieldname === "logoTicket") {
fileName = "logoTicket.jpg";
}
} else if (theme === "dark") {
if (file.fieldname === "favico") {
fileName = "favicoDark.ico";
} else if (file.fieldname === "logo") {
fileName = "logoDark.jpg";
} else if (file.fieldname === "logoTicket") {
fileName = "logoTicketDark.jpg";
}
}

const filePath = path.resolve(
__dirname,
"..",
"..",
"..",
"frontend",
"public",
"assets",
fileName
);
console.log(`Nome do arquivo gerado: ${fileName}`);
deleteIfExists(filePath);
cb(null, fileName);
}
});

const fileFilter = (
req: Request,
file: Express.Multer.File,
cb: FileFilterCallback
) => {
const allowedMimeTypes = ["image/jpeg", "image/png", "image/x-icon"];
if (allowedMimeTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(
new Error(
"Formato de arquivo inválido. Apenas .jpg, .png e .ico são permitidos."
)
);
}
};

const uploadConfig = multer({
storage,
fileFilter
});

export default uploadConfig;
89 changes: 89 additions & 0 deletions backend/src/controllers/PersonalizationController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Request, Response } from "express";
import path from "path";
import { getIO } from "../libs/socket";
import createOrUpdatePersonalization from "../services/PersonalizationServices/CreateOrUpdatePersonalizationService";
import deletePersonalization from "../services/PersonalizationServices/DeletePersonalizationService";
import listPersonalizations from "../services/PersonalizationServices/ListPersonalizationsService";

interface PersonalizationData {
theme: string;
company?: string;
url?: string;
primaryColor: string;
secondaryColor: string;
backgroundDefault: string;
backgroundPaper: string;
favico?: string | null;
logo?: string | null;
logoTicket?: string | null;
}

export const createOrUpdate = async (
req: Request,
res: Response
): Promise<Response> => {
try {
const personalizationData: PersonalizationData = req.body;
const { theme } = req.params;

if (req.files) {
const files = req.files as {
[fieldname: string]: Express.Multer.File[];
};

if (files.favico && files.favico.length > 0) {
personalizationData.favico = path.basename(files.favico[0].path);
}
if (files.logo && files.logo.length > 0) {
personalizationData.logo = path.basename(files.logo[0].path);
}
if (files.logoTicket && files.logoTicket.length > 0) {
personalizationData.logoTicket = path.basename(
files.logoTicket[0].path
);
}
}

const personalization = await createOrUpdatePersonalization({
personalizationData,
theme
});

const io = getIO();
io.emit("personalization", {
action: personalization.isNew ? "create" : "update",
personalization: personalization.data
});

return res.status(200).json(personalization.data);
} catch (error) {
return res.status(500).json({ message: error.message });
}
};

export const list = async (_req: Request, res: Response): Promise<Response> => {
try {
const personalizations = await listPersonalizations();
return res.status(200).json(personalizations);
} catch (error) {
return res.status(500).json({ message: error.message });
}
};

export const remove = async (
req: Request,
res: Response
): Promise<Response> => {
try {
const { theme } = req.params;
await deletePersonalization(theme);
const io = getIO();
io.emit("personalization", {
action: "delete",
theme
});
return res.status(204).send();
} catch (error) {
return res.status(404).json({ message: error.message });
}
};
4 changes: 3 additions & 1 deletion backend/src/database/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ContactTag from "../models/ContactTag";
import Integration from "../models/Integration";
import Message from "../models/Message";
import OldMessage from "../models/OldMessage";
import Personalization from "../models/Personalization";
import Queue from "../models/Queue";
import QuickAnswer from "../models/QuickAnswer";
import Setting from "../models/Setting";
Expand Down Expand Up @@ -36,7 +37,8 @@ const models = [
Tag,
ContactTag,
Integration,
OldMessage
OldMessage,
Personalization
];

sequelize.addModels(models);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { DataTypes, QueryInterface } from "sequelize";

module.exports = {
up: async (queryInterface: QueryInterface) => {
await queryInterface.createTable("Personalizations", {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
theme: {
type: DataTypes.STRING,
allowNull: false
},
company: {
type: DataTypes.STRING,
allowNull: false
},
url: {
type: DataTypes.STRING,
allowNull: false
},
primaryColor: {
type: DataTypes.STRING,
allowNull: false
},
secondaryColor: {
type: DataTypes.STRING,
allowNull: false
},
backgroundDefault: {
type: DataTypes.STRING,
allowNull: false
},
backgroundPaper: {
type: DataTypes.STRING,
allowNull: false
},
favico: {
type: DataTypes.TEXT,
allowNull: true
},
logo: {
type: DataTypes.TEXT,
allowNull: true
},
logoTicket: {
type: DataTypes.TEXT,
allowNull: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
}
});
},

down: async (queryInterface: QueryInterface) => {
await queryInterface.dropTable("Personalizations");
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@ module.exports = {
value: "disabled",
createdAt: new Date(),
updatedAt: new Date()
},
{
key: "darkMode",
value: "disabled",
createdAt: new Date(),
updatedAt: new Date()
}
],
{}
Expand Down
Loading

0 comments on commit 723639f

Please sign in to comment.