Initial version

This commit is contained in:
Flatlogic Bot 2025-09-19 20:44:39 +00:00
commit 1b9f5ee8bb
423 changed files with 72181 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules/
*/node_modules/
*/build/

187
502.html Normal file
View File

@ -0,0 +1,187 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Service Starting</title>
<style>
body {
font-family: sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #EFF2FF;
margin: 0;
padding: 20px;
}
.container {
text-align: center;
padding: 30px 40px;
background-color: #fff;
border-radius: 20px;
margin-bottom: 20px;
max-width: 538px;
width: 100%;
box-shadow: 0 13px 34px 0 rgba(167, 187, 242, 0.2);
box-sizing: border-box;
}
#status-heading {
font-size: 24px;
font-weight: 700;
color: #02004E;
margin-bottom: 20px;
}
h2 {
color: #333;
margin-bottom: 15px;
}
p {
color: #666;
font-size: 1.1em;
margin-bottom: 10px;
}
.tip {
font-weight: 300;
font-size: 17px;
line-height: 150%;
letter-spacing: 0;
text-align: center;
margin-top: 30px;
}
.loader-container {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.loader {
width: 100px;
aspect-ratio: 1;
border-radius: 50%;
background:
radial-gradient(farthest-side, #5C7EF1 94%, #0000) top/8px 8px no-repeat,
conic-gradient(#0000 30%, #5C7EF1);
-webkit-mask: radial-gradient(farthest-side, #0000 calc(100% - 8px), #000 0);
animation: l13 2s infinite linear;
}
@keyframes l13 {
100% {
transform: rotate(1turn)
}
}
.app-logo {
position: absolute;
width: 36px;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
margin-top: 10px;
}
.show {
display: block;
}
.project-info {
border: 1px solid #8C9DFF;
border-radius: 10px;
padding: 12px 16px;
max-width: 600px;
margin: 40px auto;
background-color: #FBFCFF;
}
.project-info h2 {
color: #02004E;
font-size: 14px;
font-weight: 500;
margin-bottom: 10px;
text-align: left;
}
.project-info p {
color: #686791;
font-size: 12px;
font-weight: 400;
text-align: left;
}
</style>
</head>
<body>
<div class="container">
<h2 id="status-heading">Loading the app, just a moment…</h2>
<p class="tip">The application is currently launching. The page will automatically refresh once site is
available.</p>
<div class="project-info">
<h2>SM Gestor</h2>
<p>ERP system for buffet and events management.</p>
</div>
<div class="loader-container">
<img src="https://flatlogic.com/blog/wp-content/uploads/2025/05/logo-bot-1.png" alt="App Logo"
class="app-logo">
<div class="loader"></div>
</div>
<div class="panel">
<video width="100%" height="315" controls loop>
<source
src="https://flatlogic.com/blog/wp-content/uploads/2025/04/20250430_1336_professional_dynamo_spinner_simple_compose_01jt349yvtenxt7xhg8hhr85j8.mp4"
type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
</div>
<script>
function checkAvailability() {
fetch('/')
.then(response => {
if (response.ok) {
window.location.reload();
} else {
setTimeout(checkAvailability, 5000);
}
})
.catch(() => {
setTimeout(checkAvailability, 5000);
});
}
document.addEventListener('DOMContentLoaded', checkAvailability);
document.addEventListener('DOMContentLoaded', function () {
const appTitle = document.querySelector('#status-heading');
const panel = document.querySelector('.panel');
const video = panel.querySelector('video');
let clickCount = 0;
appTitle.addEventListener('click', function () {
clickCount++;
if (clickCount === 5) {
panel.classList.toggle('show');
if (panel.classList.contains('show')) {
video.play();
} else {
video.pause();
}
clickCount = 0;
}
});
});
</script>
</body>
</html>

17
Dockerfile Normal file
View File

@ -0,0 +1,17 @@
FROM node:20.15.1-alpine AS builder
RUN apk add --no-cache git
WORKDIR /app
COPY frontend/package.json frontend/yarn.lock ./
RUN yarn install --pure-lockfile
COPY frontend .
RUN yarn build
FROM node:20.15.1-alpine
WORKDIR /app
COPY backend/package.json backend/yarn.lock ./
RUN yarn install --pure-lockfile
COPY backend .
COPY --from=builder /app/build /app/public
CMD ["yarn", "start"]

85
Dockerfile.dev Normal file
View File

@ -0,0 +1,85 @@
# Base image for Node.js dependencies
FROM node:20.15.1-alpine AS frontend-deps
RUN apk add --no-cache git
WORKDIR /app/frontend
COPY frontend/package.json frontend/yarn.lock ./
RUN yarn install --pure-lockfile
FROM node:20.15.1-alpine AS backend-deps
RUN apk add --no-cache git
WORKDIR /app/backend
COPY backend/package.json backend/yarn.lock ./
RUN yarn install --pure-lockfile
FROM node:20.15.1-alpine AS app-shell-deps
RUN apk add --no-cache git
WORKDIR /app/app-shell
COPY app-shell/package.json app-shell/yarn.lock ./
RUN yarn install --pure-lockfile
# Nginx setup and application build
FROM node:20.15.1-alpine AS build
RUN apk add --no-cache git nginx curl
RUN apk add --no-cache lsof procps
RUN yarn global add concurrently
RUN apk add --no-cache \
chromium \
nss \
freetype \
harfbuzz \
ttf-freefont \
fontconfig
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
RUN mkdir -p /app/pids
# Make sure to add yarn global bin to PATH
ENV PATH /root/.yarn/bin:/root/.config/yarn/global/node_modules/.bin:$PATH
# Copy dependencies
WORKDIR /app
COPY --from=frontend-deps /app/frontend /app/frontend
COPY --from=backend-deps /app/backend /app/backend
COPY --from=app-shell-deps /app/app-shell /app/app-shell
COPY frontend /app/frontend
COPY backend /app/backend
COPY app-shell /app/app-shell
COPY docker /app/docker
# Copy all files from root to /app
COPY . /app
# Copy Nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf
# Copy custom error page
COPY 502.html /usr/share/nginx/html/502.html
# Change owner and permissions of the error page
RUN chown nginx:nginx /usr/share/nginx/html/502.html && \
chmod 644 /usr/share/nginx/html/502.html
# Expose the port the app runs on
EXPOSE 8080
ENV NODE_ENV=dev_stage
ENV FRONT_PORT=3001
ENV BACKEND_PORT=3000
ENV APP_SHELL_PORT=4000
CMD ["sh", "-c", "\
yarn --cwd /app/frontend dev & echo $! > /app/pids/frontend.pid && \
yarn --cwd /app/backend start & echo $! > /app/pids/backend.pid && \
sleep 10 && nginx -g 'daemon off;' & \
NGINX_PID=$! && \
echo 'Waiting for backend (port 3000) to be available...' && \
while ! nc -z localhost ${BACKEND_PORT}; do \
sleep 2; \
done && \
echo 'Backend is up. Starting app_shell for Git check...' && \
yarn --cwd /app/app-shell start && \
wait $NGINX_PID"]

1
LICENSE Normal file
View File

@ -0,0 +1 @@
https://flatlogic.com/

200
README.md Normal file
View File

@ -0,0 +1,200 @@
# SM Gestor
## This project was generated by [Flatlogic Platform](https://flatlogic.com).
- Frontend: [React.js](https://flatlogic.com/templates?framework%5B%5D=react&sort=default)
- Backend: [NodeJS](https://flatlogic.com/templates?backend%5B%5D=nodejs&sort=default)
<details><summary>Backend Folder Structure</summary>
The generated application has the following backend folder structure:
`src` folder which contains your working files that will be used later to create the build. The src folder contains folders as:
- `auth` - config the library for authentication and authorization;
- `db` - contains such folders as:
- `api` - documentation that is automatically generated by jsdoc or other tools;
- `migrations` - is a skeleton of the database or all the actions that users do with the database;
- `models`- what will represent the database for the backend;
- `seeders` - the entity that creates the data for the database.
- `routes` - this folder would contain all the routes that you have created using Express Router and what they do would be exported from a Controller file;
- `services` - contains such folders as `emails` and `notifications`.
</details>
- Database: PostgreSQL
- app-shel: Core application framework that provides essential infrastructure services
for the entire application.
-----------------------
### We offer 2 ways how to start the project locally: by running Frontend and Backend or with Docker.
-----------------------
## To start the project:
### Backend:
> Please change current folder: `cd backend`
#### Install local dependencies:
`yarn install`
------------
#### Adjust local db:
##### 1. Install postgres:
MacOS:
`brew install postgres`
> if you dont have brew please install it (https://brew.sh) and repeat step `brew install postgres`.
Ubuntu:
`sudo apt update`
`sudo apt install postgresql postgresql-contrib`
##### 2. Create db and admin user:
Before run and test connection, make sure you have created a database as described in the above configuration. You can use the `psql` command to create a user and database.
`psql postgres --u postgres`
Next, type this command for creating a new user with password then give access for creating the database.
`postgres-# CREATE ROLE admin WITH LOGIN PASSWORD 'admin_pass';`
`postgres-# ALTER ROLE admin CREATEDB;`
Quit `psql` then log in again using the new user that previously created.
`postgres-# \q`
`psql postgres -U admin`
Type this command to creating a new database.
`postgres=> CREATE DATABASE db_{your_project_name};`
Then give that new user privileges to the new database then quit the `psql`.
`postgres=> GRANT ALL PRIVILEGES ON DATABASE db_{your_project_name} TO admin;`
`postgres=> \q`
------------
#### Create database:
`yarn db:create`
#### Start production build:
`yarn start`
### Frontend:
> Please change current folder: `cd frontend`
## To start the project with Docker:
### Description:
The project contains the **docker folder** and the `Dockerfile`.
The `Dockerfile` is used to Deploy the project to Google Cloud.
The **docker folder** contains a couple of helper scripts:
- `docker-compose.yml` (all our services: web, backend, db are described here)
- `start-backend.sh` (starts backend, but only after the database)
- `wait-for-it.sh` (imported from https://github.com/vishnubob/wait-for-it)
> To avoid breaking the application, we recommend you don't edit the following files: everything that includes the **docker folder** and `Dokerfile`.
## Run services:
1. Install docker compose (https://docs.docker.com/compose/install/)
2. Move to `docker` folder. All next steps should be done from this folder.
``` cd docker ```
3. Make executables from `wait-for-it.sh` and `start-backend.sh`:
``` chmod +x start-backend.sh && chmod +x wait-for-it.sh ```
4. Download dependend projects for services.
5. Review the docker-compose.yml file. Make sure that all services have Dockerfiles. Only db service doesn't require a Dockerfile.
6. Make sure you have needed ports (see them in `ports`) available on your local machine.
7. Start services:
7.1. With an empty database `rm -rf data && docker-compose up`
7.2. With a stored (from previus runs) database data `docker-compose up`
8. Check http://localhost:3000
9. Stop services:
9.1. Just press `Ctr+C`
## Most common errors:
1. `connection refused`
There could be many reasons, but the most common are:
- The port is not open on the destination machine.
- The port is open on the destination machine, but its backlog of pending connections is full.
- A firewall between the client and server is blocking access (also check local firewalls).
After checking for firewalls and that the port is open, use telnet to connect to the IP/port to test connectivity. This removes any potential issues from your application.
***MacOS:***
If you suspect that your SSH service might be down, you can run this command to find out:
`sudo service ssh status`
If the command line returns a status of down, then youve likely found the reason behind your connectivity error.
***Ubuntu:***
Sometimes a connection refused error can also indicate that there is an IP address conflict on your network. You can search for possible IP conflicts by running:
`arp-scan -I eth0 -l | grep <ipaddress>`
`arp-scan -I eth0 -l | grep <ipaddress>`
and
`arping <ipaddress>`
2. `yarn db:create` creates database with the assembled tables (on MacOS with Postgres database)
The workaround - put the next commands to your Postgres database terminal:
`DROP SCHEMA public CASCADE;`
`CREATE SCHEMA public;`
`GRANT ALL ON SCHEMA public TO postgres;`
`GRANT ALL ON SCHEMA public TO public;`
Afterwards, continue to start your project in the backend directory by running:
`yarn start`

26
app-shell/.eslintrc.cjs Normal file
View File

@ -0,0 +1,26 @@
const globals = require('globals');
module.exports = [
{
files: ['**/*.js', '**/*.ts', '**/*.tsx'],
languageOptions: {
ecmaVersion: 2021,
sourceType: 'module',
globals: {
...globals.browser,
...globals.node,
},
parser: '@typescript-eslint/parser',
},
plugins: ['@typescript-eslint'],
rules: {
'no-unused-vars': 'warn',
'no-console': 'off',
'indent': ['error', 2],
'quotes': ['error', 'single'],
'semi': ['error', 'always'],
'@typescript-eslint/no-unused-vars': 'warn',
},
},
];

11
app-shell/.prettierrc Normal file
View File

@ -0,0 +1,11 @@
{
"singleQuote": true,
"tabWidth": 2,
"printWidth": 80,
"trailingComma": "all",
"quoteProps": "as-needed",
"jsxSingleQuote": true,
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always"
}

7
app-shell/.sequelizerc Normal file
View File

@ -0,0 +1,7 @@
const path = require('path');
module.exports = {
"config": path.resolve("src", "db", "db.config.js"),
"models-path": path.resolve("src", "db", "models"),
"seeders-path": path.resolve("src", "db", "seeders"),
"migrations-path": path.resolve("src", "db", "migrations")
};

23
app-shell/Dockerfile Normal file
View File

@ -0,0 +1,23 @@
FROM node:20.15.1-alpine
RUN apk update && apk add bash
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN yarn install
# If you are building your code for production
# RUN npm ci --only=production
# Bundle app source
COPY . .
EXPOSE 4000
CMD [ "yarn", "start" ]

13
app-shell/README.md Normal file
View File

@ -0,0 +1,13 @@
#test - template backend,
#### Run App on local machine:
##### Install local dependencies:
- `yarn install`
---
##### Start build:
- `yarn start`

43
app-shell/package.json Normal file
View File

@ -0,0 +1,43 @@
{
"name": "app-shell",
"description": "app-shell",
"scripts": {
"start": "node ./src/index.js"
},
"dependencies": {
"@babel/parser": "^7.26.7",
"adm-zip": "^0.5.16",
"axios": "^1.6.7",
"bcrypt": "5.1.1",
"cors": "2.8.5",
"eslint": "^9.13.0",
"express": "4.18.2",
"formidable": "1.2.2",
"helmet": "4.1.1",
"json2csv": "^5.0.7",
"jsonwebtoken": "8.5.1",
"lodash": "4.17.21",
"moment": "2.30.1",
"multer": "^1.4.4",
"passport": "^0.7.0",
"passport-google-oauth2": "^0.2.0",
"passport-jwt": "^4.0.1",
"passport-microsoft": "^0.1.0",
"postcss": "^8.5.1",
"puppeteer": "^24.10.0",
"sequelize-json-schema": "^2.1.1",
"pg": "^8.13.3"
},
"engines": {
"node": ">=18"
},
"private": true,
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.12.2",
"@typescript-eslint/parser": "^8.12.2",
"cross-env": "7.0.3",
"mocha": "8.1.3",
"nodemon": "^3.1.7",
"sequelize-cli": "6.6.2"
}
}

File diff suppressed because one or more lines are too long

18
app-shell/src/config.js Normal file
View File

@ -0,0 +1,18 @@
const config = {
admin_pass: "0c22344a",
admin_email: "admin@flatlogic.com",
schema_encryption_key: process.env.SCHEMA_ENCRYPTION_KEY || '',
project_uuid: '0c22344a-db83-4477-a805-2f5b5d2d7538',
flHost: process.env.NODE_ENV === 'production' ? 'https://flatlogic.com/projects' : 'http://localhost:3000/projects',
gitea_domain: process.env.GITEA_DOMAIN || 'gitea.flatlogic.app',
gitea_username: process.env.GITEA_USERNAME || 'admin',
gitea_api_token: process.env.GITEA_API_TOKEN || null,
github_repo_url: process.env.GITHUB_REPO_URL || null,
github_token: process.env.GITHUB_TOKEN || null,
};
module.exports = config;

23
app-shell/src/helpers.js Normal file
View File

@ -0,0 +1,23 @@
const jwt = require('jsonwebtoken');
const config = require('./config');
module.exports = class Helpers {
static wrapAsync(fn) {
return function (req, res, next) {
fn(req, res, next).catch(next);
};
}
static commonErrorHandler(error, req, res, next) {
if ([400, 403, 404].includes(error.code)) {
return res.status(error.code).send(error.message);
}
console.error(error);
return res.status(500).send(error.message);
}
static jwtSign(data) {
return jwt.sign(data, config.secret_key, { expiresIn: '6h' });
}
};

54
app-shell/src/index.js Normal file
View File

@ -0,0 +1,54 @@
const express = require('express');
const cors = require('cors');
const app = express();
const bodyParser = require('body-parser');
const checkPermissions = require('./middlewares/check-permissions');
const modifyPath = require('./middlewares/modify-path');
const VCS = require('./services/vcs');
const executorRoutes = require('./routes/executor');
const vcsRoutes = require('./routes/vcs');
// Function to initialize the Git repository
function initRepo() {
const projectId = '34234';
return VCS.initRepo(projectId);
}
// Start the Express app on APP_SHELL_PORT (4000)
function startServer() {
const PORT = 4000;
app.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});
}
// Run Git check after the server is up
function runGitCheck() {
initRepo()
.then(result => {
console.log(result?.message ? result.message : result);
// Here you can add additional logic if needed
})
.catch(err => {
console.error('Error during repo initialization:', err);
// Optionally exit the process if Git check is critical:
// process.exit(1);
});
}
app.use(cors({ origin: true }));
app.use(bodyParser.json());
app.use(checkPermissions);
app.use(modifyPath);
app.use('/executor', executorRoutes);
app.use('/vcs', vcsRoutes);
// Start the app_shell server
startServer();
// Now perform Git check
runGitCheck();
module.exports = app;

View File

@ -0,0 +1,17 @@
const config = require('../config');
function checkPermissions(req, res, next) {
const project_uuid = config.project_uuid;
const requiredHeader = 'X-Project-UUID';
const headerValue = req.headers[requiredHeader.toLowerCase()];
// Logging whatever request we're getting
console.log('Request:', req.url, req.method, req.body, req.headers);
if (headerValue && headerValue === project_uuid) {
next();
} else {
res.status(403).send({ error: 'Stop right there, criminal scum! Your project UUID is invalid or missing.' });
}
}
module.exports = checkPermissions;

View File

@ -0,0 +1,8 @@
function modifyPath(req, res, next) {
if (req.body && req.body.path) {
req.body.path = '../../../' + req.body.path;
}
next();
}
module.exports = modifyPath;

View File

@ -0,0 +1,346 @@
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const fs = require('fs');
const ExecutorService = require('../services/executor');
const { takeScreenshot } = require("../services/screenshot_service");
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
router.post(
'/read_project_tree',
wrapAsync(async (req, res) => {
const { path } = req.body;
const tree = await ExecutorService.readProjectTree(path);
res.status(200).send(tree);
}),
);
router.post(
'/read_file',
wrapAsync(async (req, res) => {
const { path, showLines } = req.body;
const content = await ExecutorService.readFileContents(path, showLines);
res.status(200).send(content);
}),
);
router.post(
'/count_file_lines',
wrapAsync(async (req, res) => {
const { path } = req.body;
const content = await ExecutorService.countFileLines(path);
res.status(200).send(content);
}),
);
// router.post(
// '/read_file_header',
// wrapAsync(async (req, res) => {
// const { path, N } = req.body;
// try {
// const header = await ExecutorService.readFileHeader(path, N);
// res.status(200).send(header);
// } catch (error) {
// res.status(500).send({
// error: true,
// message: error.message,
// details: error.details || error.stack,
// validation: error.validation
// });
// }
// }),
// );
router.post(
'/read_file_line_context',
wrapAsync(async (req, res) => {
const { path, lineNumber, windowSize, showLines } = req.body;
try {
const context = await ExecutorService.readFileLineContext(path, lineNumber, windowSize, showLines);
res.status(200).send(context);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/write_file',
wrapAsync(async (req, res) => {
const { path, fileContents, comment } = req.body;
try {
await ExecutorService.writeFile(path, fileContents, comment);
res.status(200).send({ message: 'File written successfully' });
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/insert_file_content',
wrapAsync(async (req, res) => {
const { path, lineNumber, newContent, message } = req.body;
try {
await ExecutorService.insertFileContent(path, lineNumber, newContent, message);
res.status(200).send({ message: 'File written successfully' });
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/replace_file_line',
wrapAsync(async (req, res) => {
const { path, lineNumber, newText } = req.body;
try {
const result = await ExecutorService.replaceFileLine(path, lineNumber, newText);
res.status(200).send(result);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/replace_file_chunk',
wrapAsync(async (req, res) => {
const { path, startLine, endLine, newCode } = req.body;
try {
const result = await ExecutorService.replaceFileChunk(path, startLine, endLine, newCode);
res.status(200).send(result);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/delete_file_lines',
wrapAsync(async (req, res) => {
const { path, startLine, endLine, message } = req.body;
try {
const result = await ExecutorService.deleteFileLines(path, startLine, endLine, message);
res.status(200).send(result);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/validate_file',
wrapAsync(async (req, res) => {
const { path } = req.body;
try {
const validationResult = await ExecutorService.validateFile(path);
res.status(200).send({ validationResult });
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
});
}
}),
);
router.post(
'/check_frontend_runtime_error',
wrapAsync(async (req, res) => {
try {
const result = await ExecutorService.checkFrontendRuntimeLogs();
res.status(200).send(result);
} catch (error) {
res.status(500).send({ error: error });
}
}),
);
router.post(
'/replace_code_block',
wrapAsync(async (req, res) => {
const {path, oldCode, newCode, message} = req.body;
try {
const response = await ExecutorService.replaceCodeBlock(path, oldCode, newCode, message);
res.status(200).send(response);
} catch (error) {
res.status(500).send({
error: true,
message: error.message,
details: error.details || error.stack,
validation: error.validation
})
}
})
)
router.post('/update_project_files_from_scheme',
upload.single('file'), // 'file' - name of the field in the form
async (req, res) => {
console.log('Request received');
console.log('Headers:', req.headers);
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded' });
}
console.log('File info:', {
originalname: req.file.originalname,
path: req.file.path,
size: req.file.size,
mimetype: req.file.mimetype
});
try {
console.log('Starting update process...');
const result = await ExecutorService.updateProjectFilesFromScheme(req.file.path);
console.log('Update completed, result:', result);
console.log('Removing temp file...');
fs.unlinkSync(req.file.path);
console.log('Temp file removed');
console.log('Sending response...');
return res.json(result);
} catch (error) {
console.error('Error in route handler:', error);
if (req.file) {
try {
fs.unlinkSync(req.file.path);
console.log('Temp file removed after error');
} catch (unlinkError) {
console.error('Error removing temp file:', unlinkError);
}
}
console.error('Update project files error:', error);
return res.status(500).json({
error: error.message,
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
});
}
}
);
router.post(
'/get_db_schema',
wrapAsync(async (req, res) => {
try {
const jsonSchema = await ExecutorService.getDBSchema();
res.status(200).send({ jsonSchema });
} catch (error) {
res.status(500).send({ error: error });
}
}),
);
router.post(
'/execute_sql',
wrapAsync(async (req, res) => {
try {
const { query } = req.body;
const result = await ExecutorService.executeSQL(query);
res.status(200).send(result);
} catch (error) {
res.status(500).send({ error: error });
}
}),
);
router.post(
'/search_files',
wrapAsync(async (req, res) => {
try {
const { searchStrings } = req.body;
if (
typeof searchStrings !== 'string' &&
!(
Array.isArray(searchStrings) &&
searchStrings.every(item => typeof item === 'string')
)
) {
return res.status(400).send({ error: 'searchStrings must be a string or an array of strings' });
}
const result = await ExecutorService.searchFiles(searchStrings);
res.status(200).send(result);
} catch (error) {
res.status(500).send({ error: error.message });
}
}),
);
router.post(
'/screenshot',
wrapAsync(async (req, res) => {
const FRONT_PORT = process.env.FRONT_PORT || 3001;
const targetUrl = `http://localhost:${FRONT_PORT}${req.body.url || '/'}`;
const filename = req.query.filename || `screenshot-${Date.now()}.png`;
const fullPage = req.query.fullPage !== 'false';
try {
console.log(`[App-Shell/Screenshot Route]: request to take screenshot of ${targetUrl} with filename ${filename} and fullPage=${fullPage}`);
const outputPath = await takeScreenshot(targetUrl, filename, fullPage);
res.sendFile(outputPath, async (err) => {
if (err) {
console.error(`[App-Shell/Screenshot Route]: error sending screenshot ${outputPath}:`, err);
if (err.code === 'ENOENT') {
res.status(404).send('Screenshot not found.');
} else {
res.status(500).send('Error sending screenshot: ' + err.message);
}
} else {
console.log(`[App-Shell/Screenshot Route]: Screenshot sent successfully: ${outputPath}`);
}
});
} catch (error) {
console.error(`[App-Shell/Screenshot Route]: Could not take screenshot of ${targetUrl}:`, error);
res.status(500).send(`Error taking screenshot: ${error.message}`);
}
})
)
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,40 @@
const express = require('express');
const wrapAsync = require('../helpers').wrapAsync; // Ваша обёртка для обработки асинхронных маршрутов
const VSC = require('../services/vcs');
const router = express.Router();
router.post('/init', wrapAsync(async (req, res) => {
const result = await VSC.initRepo();
res.status(200).send(result);
}));
router.post('/commit', wrapAsync(async (req, res) => {
const { message, files, dev_schema } = req.body;
const result = await VSC.commitChanges(message, files, dev_schema);
res.status(200).send(result);
}));
router.post('/log', wrapAsync(async (req, res) => {
const result = await VSC.getLog();
res.status(200).send(result);
}));
router.post('/rollback', wrapAsync(async (req, res) => {
const { ref } = req.body;
// const result = await VSC.checkout(ref);
const result = await VSC.revert(ref);
res.status(200).send(result);
}));
router.post('/sync-to-stable', wrapAsync(async (req, res) => {
const result = await VSC.mergeDevIntoMaster();
res.status(200).send(result);
}));
router.post('/reset-dev', wrapAsync(async (req, res) => {
const result = await VSC.resetDevBranch();
res.status(200).send(result);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,88 @@
// Database.js
const { Client } = require('pg');
const config = require('../../../backend/src/db/db.config');
const env = process.env.NODE_ENV || 'development';
const dbConfig = config[env];
class Database {
constructor() {
this.client = new Client({
user: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
host: dbConfig.host,
port: dbConfig.port
});
// Connect once, reuse the client
this.client.connect().catch(err => {
console.error('Error connecting to the database:', err);
throw err;
});
}
async executeSQL(query) {
try {
const result = await this.client.query(query);
return {
success: true,
rows: result.rows
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
// Method to fetch simple table/column info from 'information_schema'
// (You can expand this to handle constraints, indexes, etc.)
async getDBSchema(schemaName = 'public') {
try {
const tableQuery = `
SELECT table_name
FROM information_schema.tables
WHERE table_schema = $1
AND table_type = 'BASE TABLE'
ORDER BY table_name
`;
const columnQuery = `
SELECT table_name, column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = $1
ORDER BY table_name, ordinal_position
`;
const [tablesResult, columnsResult] = await Promise.all([
this.client.query(tableQuery, [schemaName]),
this.client.query(columnQuery, [schemaName]),
]);
// Build a simple schema object:
const tables = tablesResult.rows.map(row => row.table_name);
const columnsByTable = {};
columnsResult.rows.forEach(row => {
const { table_name, column_name, data_type, is_nullable } = row;
if (!columnsByTable[table_name]) columnsByTable[table_name] = [];
columnsByTable[table_name].push({ column_name, data_type, is_nullable });
});
// Combine tables with their columns
return tables.map(table => ({
table,
columns: columnsByTable[table] || [],
}));
} catch (error) {
console.error('Error fetching schema:', error);
throw error;
}
}
async close() {
await this.client.end();
}
}
module.exports = new Database();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
const { getNotification, isNotification } = require('../helpers');
module.exports = class ForbiddenError extends Error {
constructor(messageCode) {
let message;
if (messageCode && isNotification(messageCode)) {
message = getNotification(messageCode);
}
message = message || getNotification('errors.forbidden.message');
super(message);
this.code = 403;
}
};

View File

@ -0,0 +1,16 @@
const { getNotification, isNotification } = require('../helpers');
module.exports = class ValidationError extends Error {
constructor(messageCode) {
let message;
if (messageCode && isNotification(messageCode)) {
message = getNotification(messageCode);
}
message = message || getNotification('errors.validation.message');
super(message);
this.code = 400;
}
};

View File

@ -0,0 +1,30 @@
const _get = require('lodash/get');
const errors = require('./list');
function format(message, args) {
if (!message) {
return null;
}
return message.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] != 'undefined' ? args[number] : match;
});
}
const isNotification = (key) => {
const message = _get(errors, key);
return !!message;
};
const getNotification = (key, ...args) => {
const message = _get(errors, key);
if (!message) {
return key;
}
return format(message, args);
};
exports.getNotification = getNotification;
exports.isNotification = isNotification;

View File

@ -0,0 +1,100 @@
const errors = {
app: {
title: 'test',
},
auth: {
userDisabled: 'Your account is disabled',
forbidden: 'Forbidden',
unauthorized: 'Unauthorized',
userNotFound: `Sorry, we don't recognize your credentials`,
wrongPassword: `Sorry, we don't recognize your credentials`,
weakPassword: 'This password is too weak',
emailAlreadyInUse: 'Email is already in use',
invalidEmail: 'Please provide a valid email',
passwordReset: {
invalidToken: 'Password reset link is invalid or has expired',
error: `Email not recognized`,
},
passwordUpdate: {
samePassword: `You can't use the same password. Please create new password`,
},
userNotVerified: `Sorry, your email has not been verified yet`,
emailAddressVerificationEmail: {
invalidToken: 'Email verification link is invalid or has expired',
error: `Email not recognized`,
},
},
iam: {
errors: {
userAlreadyExists: 'User with this email already exists',
userNotFound: 'User not found',
disablingHimself: `You can't disable yourself`,
revokingOwnPermission: `You can't revoke your own owner permission`,
deletingHimself: `You can't delete yourself`,
emailRequired: 'Email is required',
},
},
importer: {
errors: {
invalidFileEmpty: 'The file is empty',
invalidFileExcel: 'Only excel (.xlsx) files are allowed',
invalidFileUpload:
'Invalid file. Make sure you are using the last version of the template.',
importHashRequired: 'Import hash is required',
importHashExistent: 'Data has already been imported',
userEmailMissing: 'Some items in the CSV do not have an email',
},
},
errors: {
forbidden: {
message: 'Forbidden',
},
validation: {
message: 'An error occurred',
},
searchQueryRequired: {
message: 'Search query is required',
},
},
emails: {
invitation: {
subject: `You've been invited to {0}`,
body: `
<p>Hello,</p>
<p>You've been invited to {0} set password for your {1} account.</p>
<p><a href='{2}'>{2}</a></p>
<p>Thanks,</p>
<p>Your {0} team</p>
`,
},
emailAddressVerification: {
subject: `Verify your email for {0}`,
body: `
<p>Hello,</p>
<p>Follow this link to verify your email address.</p>
<p><a href='{0}'>{0}</a></p>
<p>If you didn't ask to verify this address, you can ignore this email.</p>
<p>Thanks,</p>
<p>Your {1} team</p>
`,
},
passwordReset: {
subject: `Reset your password for {0}`,
body: `
<p>Hello,</p>
<p>Follow this link to reset your {0} password for your {1} account.</p>
<p><a href='{2}'>{2}</a></p>
<p>If you didn't ask to reset your password, you can ignore this email.</p>
<p>Thanks,</p>
<p>Your {0} team</p>
`,
},
},
};
module.exports = errors;

View File

@ -0,0 +1,67 @@
const axios = require('axios');
const config = require('../config.js');
class ProjectEventsService {
/**
* Sends a project event to the Rails backend
*
* @param {string} eventType - Type of the event
* @param {object} payload - Event payload data
* @param {object} options - Additional options
* @param {string} [options.conversationId] - Optional conversation ID
* @param {boolean} [options.isError=false] - Whether this is an error event
* @returns {Promise<object>} - Response from the webhook
*/
static async sendEvent(eventType, payload = {}, options = {}) {
try {
console.log(`[DEBUG] Sending project event: ${eventType}`);
const webhookUrl = `https://flatlogic.com/projects/events_webhook`;
// Prepare the event data
const eventData = {
project_uuid: config.project_uuid,
event_type: eventType,
payload: {
...payload,
message: `[APP] ${payload.message}`,
is_error: options.isError || false,
system_message: true,
is_command_info: true
}
};
// Add conversation ID if provided
if (options.conversationId) {
eventData.conversation_id = options.conversationId;
}
const headers = {
'Content-Type': 'application/json',
'x-project-uuid': config.project_uuid
};
console.log(`[DEBUG] Event data: ${JSON.stringify(eventData)}`);
const response = await axios.post(webhookUrl, eventData, { headers });
console.log(`[DEBUG] Event sent successfully, status: ${response.status}`);
return response.data;
} catch (error) {
console.error(`[ERROR] Failed to send project event: ${error.message}`);
if (error.response) {
console.error(`[ERROR] Response status: ${error.response.status}`);
console.error(`[ERROR] Response data: ${JSON.stringify(error.response.data)}`);
}
// Don't throw the error, just return a failed status
// This prevents errors in the event service from breaking app functionality
return {
success: false,
error: error.message
};
}
}
}
module.exports = ProjectEventsService;

View File

@ -0,0 +1,83 @@
const puppeteer = require('puppeteer');
const path = require('path');
const fs = require('fs/promises');
const config = require('../config');
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:3000';
const SCREENSHOT_DIR = process.env.SCREENSHOT_DIR || '/tmp/screenshots';
fs.mkdir(SCREENSHOT_DIR, { recursive: true }).catch(console.error);
async function takeScreenshot(url, filename = `screenshot-${Date.now()}.png`, fullPage = true) {
let browser;
const response = await axios.post(
`${BACKEND_URL}/api/auth/signin/local`,
{ email: config.admin_email, password: config.admin_pass },
{
headers: {
'Content-Type': 'application/json',
},
}
);
const token = response.data;
const outputPath = path.join(SCREENSHOT_DIR, filename);
try {
browser = await puppeteer.launch({
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'window-size=1920,1080'
]
});
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });
if (token) {
await page.setRequestInterception(true);
page.on('request', interceptedRequest => {
if (interceptedRequest.isInterceptResolutionHandled()) {
return;
}
const headers = interceptedRequest.headers();
if (!headers['authorization'] && !headers['Authorization']) {
headers['Authorization'] = `Bearer ${token}`;
}
interceptedRequest.continue({ headers });
});
page.on('requestfailed', request => {
console.error(`[ScreenshotService]: Request failed: ${request.url()} - ${request.failure().errorText}`);
});
}
await page.goto(url, { waitUntil: 'load', timeout: 60000 });
await page.screenshot({
path: outputPath,
fullPage: true,
});
console.log(`[ScreenshotService]: Screenshot saved to ${outputPath}`);
return outputPath;
} catch (error) {
console.error(`[ScreenshotService]: Error taking screenshot: ${error.message}`);
throw error;
} finally {
if (browser) {
await browser.close();
}
}
}
module.exports = { takeScreenshot };

File diff suppressed because it is too large Load Diff

3044
app-shell/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

11
backend/.prettierrc Normal file
View File

@ -0,0 +1,11 @@
{
"singleQuote": true,
"tabWidth": 2,
"printWidth": 80,
"trailingComma": "all",
"quoteProps": "as-needed",
"jsxSingleQuote": true,
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always"
}

7
backend/.sequelizerc Normal file
View File

@ -0,0 +1,7 @@
const path = require('path');
module.exports = {
"config": path.resolve("src", "db", "db.config.js"),
"models-path": path.resolve("src", "db", "models"),
"seeders-path": path.resolve("src", "db", "seeders"),
"migrations-path": path.resolve("src", "db", "migrations")
};

23
backend/Dockerfile Normal file
View File

@ -0,0 +1,23 @@
FROM node:20.15.1-alpine
RUN apk update && apk add bash
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN yarn install
# If you are building your code for production
# RUN npm ci --only=production
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "yarn", "start" ]

67
backend/README.md Normal file
View File

@ -0,0 +1,67 @@
#SM Gestor - template backend,
#### Run App on local machine:
##### Install local dependencies:
- `yarn install`
---
##### Adjust local db:
###### 1. Install postgres:
- MacOS:
- `brew install postgres`
- Ubuntu:
- `sudo apt update`
- `sudo apt install postgresql postgresql-contrib`
###### 2. Create db and admin user:
- Before run and test connection, make sure you have created a database as described in the above configuration. You can use the `psql` command to create a user and database.
- `psql postgres --u postgres`
- Next, type this command for creating a new user with password then give access for creating the database.
- `postgres-# CREATE ROLE admin WITH LOGIN PASSWORD 'admin_pass';`
- `postgres-# ALTER ROLE admin CREATEDB;`
- Quit `psql` then log in again using the new user that previously created.
- `postgres-# \q`
- `psql postgres -U admin`
- Type this command to creating a new database.
- `postgres=> CREATE DATABASE db_sm_gestor;`
- Then give that new user privileges to the new database then quit the `psql`.
- `postgres=> GRANT ALL PRIVILEGES ON DATABASE db_sm_gestor TO admin;`
- `postgres=> \q`
---
#### Api Documentation (Swagger)
http://localhost:8080/api-docs (local host)
http://host_name/api-docs
---
##### Setup database tables or update after schema change
- `yarn db:migrate`
##### Seed the initial data (admin accounts, relevant for the first setup):
- `yarn db:seed`
##### Start build:
- `yarn start`

53
backend/package.json Normal file
View File

@ -0,0 +1,53 @@
{
"name": "smgestor",
"description": "SM Gestor - template backend",
"scripts": {
"start": "npm run db:migrate && npm run db:seed && npm run watch",
"db:migrate": "sequelize-cli db:migrate",
"db:seed": "sequelize-cli db:seed:all",
"db:drop": "sequelize-cli db:drop",
"db:create": "sequelize-cli db:create",
"watch": "node watcher.js"
},
"dependencies": {
"@google-cloud/storage": "^5.18.2",
"axios": "^1.6.7",
"bcrypt": "5.1.1",
"chokidar": "^4.0.3",
"cors": "2.8.5",
"csv-parser": "^3.0.0",
"express": "4.18.2",
"formidable": "1.2.2",
"helmet": "4.1.1",
"json2csv": "^5.0.7",
"jsonwebtoken": "8.5.1",
"lodash": "4.17.21",
"moment": "2.30.1",
"multer": "^1.4.4",
"mysql2": "2.2.5",
"nodemailer": "6.9.9",
"passport": "^0.7.0",
"passport-google-oauth2": "^0.2.0",
"passport-jwt": "^4.0.1",
"passport-microsoft": "^0.1.0",
"pg": "8.4.1",
"pg-hstore": "2.3.4",
"sequelize": "6.35.2",
"sequelize-json-schema": "^2.1.1",
"sqlite": "4.0.15",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.0",
"tedious": "^18.2.4"
},
"engines": {
"node": ">=18"
},
"private": true,
"devDependencies": {
"cross-env": "7.0.3",
"mocha": "8.1.3",
"node-mocks-http": "1.9.0",
"nodemon": "2.0.5",
"sequelize-cli": "6.6.2"
}
}

79
backend/src/auth/auth.js Normal file
View File

@ -0,0 +1,79 @@
const config = require('../config');
const providers = config.providers;
const helpers = require('../helpers');
const db = require('../db/models');
const passport = require('passport');
const JWTstrategy = require('passport-jwt').Strategy;
const ExtractJWT = require('passport-jwt').ExtractJwt;
const GoogleStrategy = require('passport-google-oauth2').Strategy;
const MicrosoftStrategy = require('passport-microsoft').Strategy;
const UsersDBApi = require('../db/api/users');
passport.use(
new JWTstrategy(
{
passReqToCallback: true,
secretOrKey: config.secret_key,
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
},
async (req, token, done) => {
try {
const user = await UsersDBApi.findBy({ email: token.user.email });
if (user && user.disabled) {
return done(new Error(`User '${user.email}' is disabled`));
}
req.currentUser = user;
return done(null, user);
} catch (error) {
done(error);
}
},
),
);
passport.use(
new GoogleStrategy(
{
clientID: config.google.clientId,
clientSecret: config.google.clientSecret,
callbackURL: config.apiUrl + '/auth/signin/google/callback',
passReqToCallback: true,
},
function (request, accessToken, refreshToken, profile, done) {
socialStrategy(profile.email, profile, providers.GOOGLE, done);
},
),
);
passport.use(
new MicrosoftStrategy(
{
clientID: config.microsoft.clientId,
clientSecret: config.microsoft.clientSecret,
callbackURL: config.apiUrl + '/auth/signin/microsoft/callback',
passReqToCallback: true,
},
function (request, accessToken, refreshToken, profile, done) {
const email = profile._json.mail || profile._json.userPrincipalName;
socialStrategy(email, profile, providers.MICROSOFT, done);
},
),
);
function socialStrategy(email, profile, provider, done) {
db.users
.findOrCreate({ where: { email, provider } })
.then(([user, created]) => {
const body = {
id: user.id,
email: user.email,
name: profile.displayName,
};
const token = helpers.jwtSign({ user: body });
return done(null, { token });
});
}

75
backend/src/config.js Normal file
View File

@ -0,0 +1,75 @@
const os = require('os');
const config = {
gcloud: {
bucket: 'fldemo-files',
hash: 'ee8b96dc219525d3542be7c0edda78fe',
},
bcrypt: {
saltRounds: 12,
},
admin_pass: '0c22344a',
user_pass: '2f5b5d2d7538',
admin_email: 'admin@flatlogic.com',
providers: {
LOCAL: 'local',
GOOGLE: 'google',
MICROSOFT: 'microsoft',
},
secret_key: process.env.SECRET_KEY || '',
remote: '',
port: process.env.NODE_ENV === 'production' ? '' : '8080',
hostUI: process.env.NODE_ENV === 'production' ? '' : 'http://localhost',
portUI: process.env.NODE_ENV === 'production' ? '' : '3000',
portUIProd: process.env.NODE_ENV === 'production' ? '' : ':3000',
swaggerUI: process.env.NODE_ENV === 'production' ? '' : 'http://localhost',
swaggerPort: process.env.NODE_ENV === 'production' ? '' : ':8080',
google: {
clientId: process.env.GOOGLE_CLIENT_ID || '',
clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',
},
microsoft: {
clientId: process.env.MS_CLIENT_ID || '',
clientSecret: process.env.MS_CLIENT_SECRET || '',
},
uploadDir: os.tmpdir(),
email: {
from: 'SM Gestor <app@flatlogic.app>',
host: 'email-smtp.us-east-1.amazonaws.com',
port: 587,
auth: {
user: process.env.EMAIL_USER || '',
pass: process.env.EMAIL_PASS,
},
tls: {
rejectUnauthorized: false,
},
},
roles: {
admin: 'Administrator',
user: 'Support Staff',
},
project_uuid: '0c22344a-db83-4477-a805-2f5b5d2d7538',
flHost:
process.env.NODE_ENV === 'production' ||
process.env.NODE_ENV === 'dev_stage'
? 'https://flatlogic.com/projects'
: 'http://localhost:3000/projects',
gpt_key: process.env.GPT_KEY || '',
};
config.pexelsKey = process.env.PEXELS_KEY || '';
config.pexelsQuery = 'Abstract business management concept';
config.host =
process.env.NODE_ENV === 'production' ? config.remote : 'http://localhost';
config.apiUrl = `${config.host}${config.port ? `:${config.port}` : ``}/api`;
config.swaggerUrl = `${config.swaggerUI}${config.swaggerPort}`;
config.uiUrl = `${config.hostUI}${config.portUI ? `:${config.portUI}` : ``}/#`;
config.backUrl = `${config.hostUI}${config.portUI ? `:${config.portUI}` : ``}`;
module.exports = config;

View File

@ -0,0 +1,360 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class ClientesDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const clientes = await db.clientes.create(
{
id: data.id || undefined,
nome_completo: data.nome_completo || null,
telefone_principal: data.telefone_principal || null,
endereco: data.endereco || null,
telefone_secundario: data.telefone_secundario || null,
email: data.email || null,
rg: data.rg || null,
cpf: data.cpf || null,
estado_civil: data.estado_civil || null,
profissao: data.profissao || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
return clientes;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const clientesData = data.map((item, index) => ({
id: item.id || undefined,
nome_completo: item.nome_completo || null,
telefone_principal: item.telefone_principal || null,
endereco: item.endereco || null,
telefone_secundario: item.telefone_secundario || null,
email: item.email || null,
rg: item.rg || null,
cpf: item.cpf || null,
estado_civil: item.estado_civil || null,
profissao: item.profissao || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const clientes = await db.clientes.bulkCreate(clientesData, {
transaction,
});
// For each item created, replace relation files
return clientes;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const clientes = await db.clientes.findByPk(id, {}, { transaction });
const updatePayload = {};
if (data.nome_completo !== undefined)
updatePayload.nome_completo = data.nome_completo;
if (data.telefone_principal !== undefined)
updatePayload.telefone_principal = data.telefone_principal;
if (data.endereco !== undefined) updatePayload.endereco = data.endereco;
if (data.telefone_secundario !== undefined)
updatePayload.telefone_secundario = data.telefone_secundario;
if (data.email !== undefined) updatePayload.email = data.email;
if (data.rg !== undefined) updatePayload.rg = data.rg;
if (data.cpf !== undefined) updatePayload.cpf = data.cpf;
if (data.estado_civil !== undefined)
updatePayload.estado_civil = data.estado_civil;
if (data.profissao !== undefined) updatePayload.profissao = data.profissao;
updatePayload.updatedById = currentUser.id;
await clientes.update(updatePayload, { transaction });
return clientes;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const clientes = await db.clientes.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of clientes) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of clientes) {
await record.destroy({ transaction });
}
});
return clientes;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const clientes = await db.clientes.findByPk(id, options);
await clientes.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await clientes.destroy({
transaction,
});
return clientes;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const clientes = await db.clientes.findOne({ where }, { transaction });
if (!clientes) {
return clientes;
}
const output = clientes.get({ plain: true });
output.orcamentos_cliente = await clientes.getOrcamentos_cliente({
transaction,
});
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.nome_completo) {
where = {
...where,
[Op.and]: Utils.ilike(
'clientes',
'nome_completo',
filter.nome_completo,
),
};
}
if (filter.telefone_principal) {
where = {
...where,
[Op.and]: Utils.ilike(
'clientes',
'telefone_principal',
filter.telefone_principal,
),
};
}
if (filter.endereco) {
where = {
...where,
[Op.and]: Utils.ilike('clientes', 'endereco', filter.endereco),
};
}
if (filter.telefone_secundario) {
where = {
...where,
[Op.and]: Utils.ilike(
'clientes',
'telefone_secundario',
filter.telefone_secundario,
),
};
}
if (filter.email) {
where = {
...where,
[Op.and]: Utils.ilike('clientes', 'email', filter.email),
};
}
if (filter.rg) {
where = {
...where,
[Op.and]: Utils.ilike('clientes', 'rg', filter.rg),
};
}
if (filter.cpf) {
where = {
...where,
[Op.and]: Utils.ilike('clientes', 'cpf', filter.cpf),
};
}
if (filter.estado_civil) {
where = {
...where,
[Op.and]: Utils.ilike(
'clientes',
'estado_civil',
filter.estado_civil,
),
};
}
if (filter.profissao) {
where = {
...where,
[Op.and]: Utils.ilike('clientes', 'profissao', filter.profissao),
};
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.clientes.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('clientes', 'nome_completo', query),
],
};
}
const records = await db.clientes.findAll({
attributes: ['id', 'nome_completo'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['nome_completo', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.nome_completo,
}));
}
};

View File

@ -0,0 +1,373 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Contas_a_pagarDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const contas_a_pagar = await db.contas_a_pagar.create(
{
id: data.id || undefined,
descricao_da_despesa: data.descricao_da_despesa || null,
data_de_vencimento: data.data_de_vencimento || null,
valor: data.valor || null,
status: data.status || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await contas_a_pagar.setFornecedor(data.fornecedor || null, {
transaction,
});
return contas_a_pagar;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const contas_a_pagarData = data.map((item, index) => ({
id: item.id || undefined,
descricao_da_despesa: item.descricao_da_despesa || null,
data_de_vencimento: item.data_de_vencimento || null,
valor: item.valor || null,
status: item.status || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const contas_a_pagar = await db.contas_a_pagar.bulkCreate(
contas_a_pagarData,
{ transaction },
);
// For each item created, replace relation files
return contas_a_pagar;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const contas_a_pagar = await db.contas_a_pagar.findByPk(
id,
{},
{ transaction },
);
const updatePayload = {};
if (data.descricao_da_despesa !== undefined)
updatePayload.descricao_da_despesa = data.descricao_da_despesa;
if (data.data_de_vencimento !== undefined)
updatePayload.data_de_vencimento = data.data_de_vencimento;
if (data.valor !== undefined) updatePayload.valor = data.valor;
if (data.status !== undefined) updatePayload.status = data.status;
updatePayload.updatedById = currentUser.id;
await contas_a_pagar.update(updatePayload, { transaction });
if (data.fornecedor !== undefined) {
await contas_a_pagar.setFornecedor(
data.fornecedor,
{ transaction },
);
}
return contas_a_pagar;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const contas_a_pagar = await db.contas_a_pagar.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of contas_a_pagar) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of contas_a_pagar) {
await record.destroy({ transaction });
}
});
return contas_a_pagar;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const contas_a_pagar = await db.contas_a_pagar.findByPk(id, options);
await contas_a_pagar.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await contas_a_pagar.destroy({
transaction,
});
return contas_a_pagar;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const contas_a_pagar = await db.contas_a_pagar.findOne(
{ where },
{ transaction },
);
if (!contas_a_pagar) {
return contas_a_pagar;
}
const output = contas_a_pagar.get({ plain: true });
output.fornecedor = await contas_a_pagar.getFornecedor({
transaction,
});
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [
{
model: db.fornecedores,
as: 'fornecedor',
where: filter.fornecedor
? {
[Op.or]: [
{
id: {
[Op.in]: filter.fornecedor
.split('|')
.map((term) => Utils.uuid(term)),
},
},
{
nome_fornecedor: {
[Op.or]: filter.fornecedor
.split('|')
.map((term) => ({ [Op.iLike]: `%${term}%` })),
},
},
],
}
: {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.descricao_da_despesa) {
where = {
...where,
[Op.and]: Utils.ilike(
'contas_a_pagar',
'descricao_da_despesa',
filter.descricao_da_despesa,
),
};
}
if (filter.data_de_vencimentoRange) {
const [start, end] = filter.data_de_vencimentoRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
data_de_vencimento: {
...where.data_de_vencimento,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
data_de_vencimento: {
...where.data_de_vencimento,
[Op.lte]: end,
},
};
}
}
if (filter.valorRange) {
const [start, end] = filter.valorRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
valor: {
...where.valor,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
valor: {
...where.valor,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.status) {
where = {
...where,
status: filter.status,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.contas_a_pagar.findAndCountAll(
queryOptions,
);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('contas_a_pagar', 'descricao_da_despesa', query),
],
};
}
const records = await db.contas_a_pagar.findAll({
attributes: ['id', 'descricao_da_despesa'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['descricao_da_despesa', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.descricao_da_despesa,
}));
}
};

View File

@ -0,0 +1,374 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Contas_a_receberDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const contas_a_receber = await db.contas_a_receber.create(
{
id: data.id || undefined,
descricao_da_parcela: data.descricao_da_parcela || null,
data_de_vencimento: data.data_de_vencimento || null,
valor_da_parcela: data.valor_da_parcela || null,
status: data.status || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await contas_a_receber.setOrcamento(data.orcamento || null, {
transaction,
});
return contas_a_receber;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const contas_a_receberData = data.map((item, index) => ({
id: item.id || undefined,
descricao_da_parcela: item.descricao_da_parcela || null,
data_de_vencimento: item.data_de_vencimento || null,
valor_da_parcela: item.valor_da_parcela || null,
status: item.status || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const contas_a_receber = await db.contas_a_receber.bulkCreate(
contas_a_receberData,
{ transaction },
);
// For each item created, replace relation files
return contas_a_receber;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const contas_a_receber = await db.contas_a_receber.findByPk(
id,
{},
{ transaction },
);
const updatePayload = {};
if (data.descricao_da_parcela !== undefined)
updatePayload.descricao_da_parcela = data.descricao_da_parcela;
if (data.data_de_vencimento !== undefined)
updatePayload.data_de_vencimento = data.data_de_vencimento;
if (data.valor_da_parcela !== undefined)
updatePayload.valor_da_parcela = data.valor_da_parcela;
if (data.status !== undefined) updatePayload.status = data.status;
updatePayload.updatedById = currentUser.id;
await contas_a_receber.update(updatePayload, { transaction });
if (data.orcamento !== undefined) {
await contas_a_receber.setOrcamento(
data.orcamento,
{ transaction },
);
}
return contas_a_receber;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const contas_a_receber = await db.contas_a_receber.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of contas_a_receber) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of contas_a_receber) {
await record.destroy({ transaction });
}
});
return contas_a_receber;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const contas_a_receber = await db.contas_a_receber.findByPk(id, options);
await contas_a_receber.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await contas_a_receber.destroy({
transaction,
});
return contas_a_receber;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const contas_a_receber = await db.contas_a_receber.findOne(
{ where },
{ transaction },
);
if (!contas_a_receber) {
return contas_a_receber;
}
const output = contas_a_receber.get({ plain: true });
output.orcamento = await contas_a_receber.getOrcamento({
transaction,
});
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [
{
model: db.orcamentos,
as: 'orcamento',
where: filter.orcamento
? {
[Op.or]: [
{
id: {
[Op.in]: filter.orcamento
.split('|')
.map((term) => Utils.uuid(term)),
},
},
{
id_orcamento: {
[Op.or]: filter.orcamento
.split('|')
.map((term) => ({ [Op.iLike]: `%${term}%` })),
},
},
],
}
: {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.descricao_da_parcela) {
where = {
...where,
[Op.and]: Utils.ilike(
'contas_a_receber',
'descricao_da_parcela',
filter.descricao_da_parcela,
),
};
}
if (filter.data_de_vencimentoRange) {
const [start, end] = filter.data_de_vencimentoRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
data_de_vencimento: {
...where.data_de_vencimento,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
data_de_vencimento: {
...where.data_de_vencimento,
[Op.lte]: end,
},
};
}
}
if (filter.valor_da_parcelaRange) {
const [start, end] = filter.valor_da_parcelaRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
valor_da_parcela: {
...where.valor_da_parcela,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
valor_da_parcela: {
...where.valor_da_parcela,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.status) {
where = {
...where,
status: filter.status,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.contas_a_receber.findAndCountAll(
queryOptions,
);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('contas_a_receber', 'descricao_da_parcela', query),
],
};
}
const records = await db.contas_a_receber.findAll({
attributes: ['id', 'descricao_da_parcela'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['descricao_da_parcela', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.descricao_da_parcela,
}));
}
};

View File

@ -0,0 +1,73 @@
const db = require('../models');
const assert = require('assert');
const services = require('../../services/file');
module.exports = class FileDBApi {
static async replaceRelationFiles(relation, rawFiles, options) {
assert(relation.belongsTo, 'belongsTo is required');
assert(relation.belongsToColumn, 'belongsToColumn is required');
assert(relation.belongsToId, 'belongsToId is required');
let files = [];
if (Array.isArray(rawFiles)) {
files = rawFiles;
} else {
files = rawFiles ? [rawFiles] : [];
}
await this._removeLegacyFiles(relation, files, options);
await this._addFiles(relation, files, options);
}
static async _addFiles(relation, files, options) {
const transaction = (options && options.transaction) || undefined;
const currentUser = (options && options.currentUser) || { id: null };
const inexistentFiles = files.filter((file) => !!file.new);
for (const file of inexistentFiles) {
await db.file.create(
{
belongsTo: relation.belongsTo,
belongsToColumn: relation.belongsToColumn,
belongsToId: relation.belongsToId,
name: file.name,
sizeInBytes: file.sizeInBytes,
privateUrl: file.privateUrl,
publicUrl: file.publicUrl,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{
transaction,
},
);
}
}
static async _removeLegacyFiles(relation, files, options) {
const transaction = (options && options.transaction) || undefined;
const filesToDelete = await db.file.findAll({
where: {
belongsTo: relation.belongsTo,
belongsToId: relation.belongsToId,
belongsToColumn: relation.belongsToColumn,
id: {
[db.Sequelize.Op.notIn]: files
.filter((file) => !file.new)
.map((file) => file.id),
},
},
transaction,
});
for (let file of filesToDelete) {
await services.deleteGCloud(file.privateUrl);
await file.destroy({
transaction,
});
}
}
};

View File

@ -0,0 +1,316 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class FornecedoresDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const fornecedores = await db.fornecedores.create(
{
id: data.id || undefined,
nome_fornecedor: data.nome_fornecedor || null,
cnpj_cpf: data.cnpj_cpf || null,
contato_principal: data.contato_principal || null,
telefone: data.telefone || null,
email: data.email || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
return fornecedores;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const fornecedoresData = data.map((item, index) => ({
id: item.id || undefined,
nome_fornecedor: item.nome_fornecedor || null,
cnpj_cpf: item.cnpj_cpf || null,
contato_principal: item.contato_principal || null,
telefone: item.telefone || null,
email: item.email || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const fornecedores = await db.fornecedores.bulkCreate(fornecedoresData, {
transaction,
});
// For each item created, replace relation files
return fornecedores;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const fornecedores = await db.fornecedores.findByPk(
id,
{},
{ transaction },
);
const updatePayload = {};
if (data.nome_fornecedor !== undefined)
updatePayload.nome_fornecedor = data.nome_fornecedor;
if (data.cnpj_cpf !== undefined) updatePayload.cnpj_cpf = data.cnpj_cpf;
if (data.contato_principal !== undefined)
updatePayload.contato_principal = data.contato_principal;
if (data.telefone !== undefined) updatePayload.telefone = data.telefone;
if (data.email !== undefined) updatePayload.email = data.email;
updatePayload.updatedById = currentUser.id;
await fornecedores.update(updatePayload, { transaction });
return fornecedores;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const fornecedores = await db.fornecedores.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of fornecedores) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of fornecedores) {
await record.destroy({ transaction });
}
});
return fornecedores;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const fornecedores = await db.fornecedores.findByPk(id, options);
await fornecedores.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await fornecedores.destroy({
transaction,
});
return fornecedores;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const fornecedores = await db.fornecedores.findOne(
{ where },
{ transaction },
);
if (!fornecedores) {
return fornecedores;
}
const output = fornecedores.get({ plain: true });
output.contas_a_pagar_fornecedor =
await fornecedores.getContas_a_pagar_fornecedor({
transaction,
});
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.nome_fornecedor) {
where = {
...where,
[Op.and]: Utils.ilike(
'fornecedores',
'nome_fornecedor',
filter.nome_fornecedor,
),
};
}
if (filter.cnpj_cpf) {
where = {
...where,
[Op.and]: Utils.ilike('fornecedores', 'cnpj_cpf', filter.cnpj_cpf),
};
}
if (filter.contato_principal) {
where = {
...where,
[Op.and]: Utils.ilike(
'fornecedores',
'contato_principal',
filter.contato_principal,
),
};
}
if (filter.telefone) {
where = {
...where,
[Op.and]: Utils.ilike('fornecedores', 'telefone', filter.telefone),
};
}
if (filter.email) {
where = {
...where,
[Op.and]: Utils.ilike('fornecedores', 'email', filter.email),
};
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.fornecedores.findAndCountAll(
queryOptions,
);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('fornecedores', 'nome_fornecedor', query),
],
};
}
const records = await db.fornecedores.findAll({
attributes: ['id', 'nome_fornecedor'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['nome_fornecedor', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.nome_fornecedor,
}));
}
};

View File

@ -0,0 +1,317 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class FuncionariosDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const funcionarios = await db.funcionarios.create(
{
id: data.id || undefined,
nome_completo: data.nome_completo || null,
cargo: data.cargo || null,
telefone: data.telefone || null,
email: data.email || null,
endereco: data.endereco || null,
descricao: data.descricao || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
return funcionarios;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const funcionariosData = data.map((item, index) => ({
id: item.id || undefined,
nome_completo: item.nome_completo || null,
cargo: item.cargo || null,
telefone: item.telefone || null,
email: item.email || null,
endereco: item.endereco || null,
descricao: item.descricao || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const funcionarios = await db.funcionarios.bulkCreate(funcionariosData, {
transaction,
});
// For each item created, replace relation files
return funcionarios;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const funcionarios = await db.funcionarios.findByPk(
id,
{},
{ transaction },
);
const updatePayload = {};
if (data.nome_completo !== undefined)
updatePayload.nome_completo = data.nome_completo;
if (data.cargo !== undefined) updatePayload.cargo = data.cargo;
if (data.telefone !== undefined) updatePayload.telefone = data.telefone;
if (data.email !== undefined) updatePayload.email = data.email;
if (data.endereco !== undefined) updatePayload.endereco = data.endereco;
if (data.descricao !== undefined) updatePayload.descricao = data.descricao;
updatePayload.updatedById = currentUser.id;
await funcionarios.update(updatePayload, { transaction });
return funcionarios;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const funcionarios = await db.funcionarios.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of funcionarios) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of funcionarios) {
await record.destroy({ transaction });
}
});
return funcionarios;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const funcionarios = await db.funcionarios.findByPk(id, options);
await funcionarios.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await funcionarios.destroy({
transaction,
});
return funcionarios;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const funcionarios = await db.funcionarios.findOne(
{ where },
{ transaction },
);
if (!funcionarios) {
return funcionarios;
}
const output = funcionarios.get({ plain: true });
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.nome_completo) {
where = {
...where,
[Op.and]: Utils.ilike(
'funcionarios',
'nome_completo',
filter.nome_completo,
),
};
}
if (filter.cargo) {
where = {
...where,
[Op.and]: Utils.ilike('funcionarios', 'cargo', filter.cargo),
};
}
if (filter.telefone) {
where = {
...where,
[Op.and]: Utils.ilike('funcionarios', 'telefone', filter.telefone),
};
}
if (filter.email) {
where = {
...where,
[Op.and]: Utils.ilike('funcionarios', 'email', filter.email),
};
}
if (filter.endereco) {
where = {
...where,
[Op.and]: Utils.ilike('funcionarios', 'endereco', filter.endereco),
};
}
if (filter.descricao) {
where = {
...where,
[Op.and]: Utils.ilike('funcionarios', 'descricao', filter.descricao),
};
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.funcionarios.findAndCountAll(
queryOptions,
);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('funcionarios', 'nome_completo', query),
],
};
}
const records = await db.funcionarios.findAll({
attributes: ['id', 'nome_completo'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['nome_completo', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.nome_completo,
}));
}
};

View File

@ -0,0 +1,391 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Itens_do_orcamentoDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const itens_do_orcamento = await db.itens_do_orcamento.create(
{
id: data.id || undefined,
quantidade: data.quantidade || null,
subtotal: data.subtotal || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await itens_do_orcamento.setOrcamento(data.orcamento || null, {
transaction,
});
await itens_do_orcamento.setServico_produto(data.servico_produto || null, {
transaction,
});
return itens_do_orcamento;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const itens_do_orcamentoData = data.map((item, index) => ({
id: item.id || undefined,
quantidade: item.quantidade || null,
subtotal: item.subtotal || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const itens_do_orcamento = await db.itens_do_orcamento.bulkCreate(
itens_do_orcamentoData,
{ transaction },
);
// For each item created, replace relation files
return itens_do_orcamento;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const itens_do_orcamento = await db.itens_do_orcamento.findByPk(
id,
{},
{ transaction },
);
const updatePayload = {};
if (data.quantidade !== undefined)
updatePayload.quantidade = data.quantidade;
if (data.subtotal !== undefined) updatePayload.subtotal = data.subtotal;
updatePayload.updatedById = currentUser.id;
await itens_do_orcamento.update(updatePayload, { transaction });
if (data.orcamento !== undefined) {
await itens_do_orcamento.setOrcamento(
data.orcamento,
{ transaction },
);
}
if (data.servico_produto !== undefined) {
await itens_do_orcamento.setServico_produto(
data.servico_produto,
{ transaction },
);
}
return itens_do_orcamento;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const itens_do_orcamento = await db.itens_do_orcamento.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of itens_do_orcamento) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of itens_do_orcamento) {
await record.destroy({ transaction });
}
});
return itens_do_orcamento;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const itens_do_orcamento = await db.itens_do_orcamento.findByPk(
id,
options,
);
await itens_do_orcamento.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await itens_do_orcamento.destroy({
transaction,
});
return itens_do_orcamento;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const itens_do_orcamento = await db.itens_do_orcamento.findOne(
{ where },
{ transaction },
);
if (!itens_do_orcamento) {
return itens_do_orcamento;
}
const output = itens_do_orcamento.get({ plain: true });
output.orcamento = await itens_do_orcamento.getOrcamento({
transaction,
});
output.servico_produto = await itens_do_orcamento.getServico_produto({
transaction,
});
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [
{
model: db.orcamentos,
as: 'orcamento',
where: filter.orcamento
? {
[Op.or]: [
{
id: {
[Op.in]: filter.orcamento
.split('|')
.map((term) => Utils.uuid(term)),
},
},
{
id_orcamento: {
[Op.or]: filter.orcamento
.split('|')
.map((term) => ({ [Op.iLike]: `%${term}%` })),
},
},
],
}
: {},
},
{
model: db.servicos_produtos,
as: 'servico_produto',
where: filter.servico_produto
? {
[Op.or]: [
{
id: {
[Op.in]: filter.servico_produto
.split('|')
.map((term) => Utils.uuid(term)),
},
},
{
nome_do_item: {
[Op.or]: filter.servico_produto
.split('|')
.map((term) => ({ [Op.iLike]: `%${term}%` })),
},
},
],
}
: {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.quantidadeRange) {
const [start, end] = filter.quantidadeRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
quantidade: {
...where.quantidade,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
quantidade: {
...where.quantidade,
[Op.lte]: end,
},
};
}
}
if (filter.subtotalRange) {
const [start, end] = filter.subtotalRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
subtotal: {
...where.subtotal,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
subtotal: {
...where.subtotal,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.itens_do_orcamento.findAndCountAll(
queryOptions,
);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('itens_do_orcamento', 'orcamento', query),
],
};
}
const records = await db.itens_do_orcamento.findAll({
attributes: ['id', 'orcamento'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['orcamento', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.orcamento,
}));
}
};

View File

@ -0,0 +1,523 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class OrcamentosDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const orcamentos = await db.orcamentos.create(
{
id: data.id || undefined,
id_orcamento: data.id_orcamento || null,
data_do_evento: data.data_do_evento || null,
local_do_evento: data.local_do_evento || null,
status: data.status || null,
tipo_desconto: data.tipo_desconto || null,
valor_desconto: data.valor_desconto || null,
valor_entrada: data.valor_entrada || null,
forma_de_pagamento: data.forma_de_pagamento || null,
quantidade_parcelas: data.quantidade_parcelas || null,
valor_total: data.valor_total || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await orcamentos.setCliente(data.cliente || null, {
transaction,
});
return orcamentos;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const orcamentosData = data.map((item, index) => ({
id: item.id || undefined,
id_orcamento: item.id_orcamento || null,
data_do_evento: item.data_do_evento || null,
local_do_evento: item.local_do_evento || null,
status: item.status || null,
tipo_desconto: item.tipo_desconto || null,
valor_desconto: item.valor_desconto || null,
valor_entrada: item.valor_entrada || null,
forma_de_pagamento: item.forma_de_pagamento || null,
quantidade_parcelas: item.quantidade_parcelas || null,
valor_total: item.valor_total || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const orcamentos = await db.orcamentos.bulkCreate(orcamentosData, {
transaction,
});
// For each item created, replace relation files
return orcamentos;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const orcamentos = await db.orcamentos.findByPk(id, {}, { transaction });
const updatePayload = {};
if (data.id_orcamento !== undefined)
updatePayload.id_orcamento = data.id_orcamento;
if (data.data_do_evento !== undefined)
updatePayload.data_do_evento = data.data_do_evento;
if (data.local_do_evento !== undefined)
updatePayload.local_do_evento = data.local_do_evento;
if (data.status !== undefined) updatePayload.status = data.status;
if (data.tipo_desconto !== undefined)
updatePayload.tipo_desconto = data.tipo_desconto;
if (data.valor_desconto !== undefined)
updatePayload.valor_desconto = data.valor_desconto;
if (data.valor_entrada !== undefined)
updatePayload.valor_entrada = data.valor_entrada;
if (data.forma_de_pagamento !== undefined)
updatePayload.forma_de_pagamento = data.forma_de_pagamento;
if (data.quantidade_parcelas !== undefined)
updatePayload.quantidade_parcelas = data.quantidade_parcelas;
if (data.valor_total !== undefined)
updatePayload.valor_total = data.valor_total;
updatePayload.updatedById = currentUser.id;
await orcamentos.update(updatePayload, { transaction });
if (data.cliente !== undefined) {
await orcamentos.setCliente(
data.cliente,
{ transaction },
);
}
return orcamentos;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const orcamentos = await db.orcamentos.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of orcamentos) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of orcamentos) {
await record.destroy({ transaction });
}
});
return orcamentos;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const orcamentos = await db.orcamentos.findByPk(id, options);
await orcamentos.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await orcamentos.destroy({
transaction,
});
return orcamentos;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const orcamentos = await db.orcamentos.findOne({ where }, { transaction });
if (!orcamentos) {
return orcamentos;
}
const output = orcamentos.get({ plain: true });
output.contas_a_receber_orcamento =
await orcamentos.getContas_a_receber_orcamento({
transaction,
});
output.itens_do_orcamento_orcamento =
await orcamentos.getItens_do_orcamento_orcamento({
transaction,
});
output.cliente = await orcamentos.getCliente({
transaction,
});
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [
{
model: db.clientes,
as: 'cliente',
where: filter.cliente
? {
[Op.or]: [
{
id: {
[Op.in]: filter.cliente
.split('|')
.map((term) => Utils.uuid(term)),
},
},
{
nome_completo: {
[Op.or]: filter.cliente
.split('|')
.map((term) => ({ [Op.iLike]: `%${term}%` })),
},
},
],
}
: {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.id_orcamento) {
where = {
...where,
[Op.and]: Utils.ilike(
'orcamentos',
'id_orcamento',
filter.id_orcamento,
),
};
}
if (filter.local_do_evento) {
where = {
...where,
[Op.and]: Utils.ilike(
'orcamentos',
'local_do_evento',
filter.local_do_evento,
),
};
}
if (filter.forma_de_pagamento) {
where = {
...where,
[Op.and]: Utils.ilike(
'orcamentos',
'forma_de_pagamento',
filter.forma_de_pagamento,
),
};
}
if (filter.calendarStart && filter.calendarEnd) {
where = {
...where,
[Op.or]: [
{
data_do_evento: {
[Op.between]: [filter.calendarStart, filter.calendarEnd],
},
},
{
data_do_evento: {
[Op.between]: [filter.calendarStart, filter.calendarEnd],
},
},
],
};
}
if (filter.data_do_eventoRange) {
const [start, end] = filter.data_do_eventoRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
data_do_evento: {
...where.data_do_evento,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
data_do_evento: {
...where.data_do_evento,
[Op.lte]: end,
},
};
}
}
if (filter.valor_descontoRange) {
const [start, end] = filter.valor_descontoRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
valor_desconto: {
...where.valor_desconto,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
valor_desconto: {
...where.valor_desconto,
[Op.lte]: end,
},
};
}
}
if (filter.valor_entradaRange) {
const [start, end] = filter.valor_entradaRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
valor_entrada: {
...where.valor_entrada,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
valor_entrada: {
...where.valor_entrada,
[Op.lte]: end,
},
};
}
}
if (filter.quantidade_parcelasRange) {
const [start, end] = filter.quantidade_parcelasRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
quantidade_parcelas: {
...where.quantidade_parcelas,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
quantidade_parcelas: {
...where.quantidade_parcelas,
[Op.lte]: end,
},
};
}
}
if (filter.valor_totalRange) {
const [start, end] = filter.valor_totalRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
valor_total: {
...where.valor_total,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
valor_total: {
...where.valor_total,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.status) {
where = {
...where,
status: filter.status,
};
}
if (filter.tipo_desconto) {
where = {
...where,
tipo_desconto: filter.tipo_desconto,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.orcamentos.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('orcamentos', 'id_orcamento', query),
],
};
}
const records = await db.orcamentos.findAll({
attributes: ['id', 'id_orcamento'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['id_orcamento', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.id_orcamento,
}));
}
};

View File

@ -0,0 +1,253 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class PermissionsDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.create(
{
id: data.id || undefined,
name: data.name || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
return permissions;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const permissionsData = data.map((item, index) => ({
id: item.id || undefined,
name: item.name || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const permissions = await db.permissions.bulkCreate(permissionsData, {
transaction,
});
// For each item created, replace relation files
return permissions;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.findByPk(id, {}, { transaction });
const updatePayload = {};
if (data.name !== undefined) updatePayload.name = data.name;
updatePayload.updatedById = currentUser.id;
await permissions.update(updatePayload, { transaction });
return permissions;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of permissions) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of permissions) {
await record.destroy({ transaction });
}
});
return permissions;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.findByPk(id, options);
await permissions.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await permissions.destroy({
transaction,
});
return permissions;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.findOne(
{ where },
{ transaction },
);
if (!permissions) {
return permissions;
}
const output = permissions.get({ plain: true });
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike('permissions', 'name', filter.name),
};
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.permissions.findAndCountAll(
queryOptions,
);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('permissions', 'name', query),
],
};
}
const records = await db.permissions.findAll({
attributes: ['id', 'name'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};

316
backend/src/db/api/roles.js Normal file
View File

@ -0,0 +1,316 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class RolesDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const roles = await db.roles.create(
{
id: data.id || undefined,
name: data.name || null,
role_customization: data.role_customization || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await roles.setPermissions(data.permissions || [], {
transaction,
});
return roles;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const rolesData = data.map((item, index) => ({
id: item.id || undefined,
name: item.name || null,
role_customization: item.role_customization || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const roles = await db.roles.bulkCreate(rolesData, { transaction });
// For each item created, replace relation files
return roles;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const roles = await db.roles.findByPk(id, {}, { transaction });
const updatePayload = {};
if (data.name !== undefined) updatePayload.name = data.name;
if (data.role_customization !== undefined)
updatePayload.role_customization = data.role_customization;
updatePayload.updatedById = currentUser.id;
await roles.update(updatePayload, { transaction });
if (data.permissions !== undefined) {
await roles.setPermissions(data.permissions, { transaction });
}
return roles;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const roles = await db.roles.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of roles) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of roles) {
await record.destroy({ transaction });
}
});
return roles;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const roles = await db.roles.findByPk(id, options);
await roles.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await roles.destroy({
transaction,
});
return roles;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const roles = await db.roles.findOne({ where }, { transaction });
if (!roles) {
return roles;
}
const output = roles.get({ plain: true });
output.users_app_role = await roles.getUsers_app_role({
transaction,
});
output.permissions = await roles.getPermissions({
transaction,
});
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [
{
model: db.permissions,
as: 'permissions',
required: false,
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike('roles', 'name', filter.name),
};
}
if (filter.role_customization) {
where = {
...where,
[Op.and]: Utils.ilike(
'roles',
'role_customization',
filter.role_customization,
),
};
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.permissions) {
const searchTerms = filter.permissions.split('|');
include = [
{
model: db.permissions,
as: 'permissions_filter',
required: searchTerms.length > 0,
where:
searchTerms.length > 0
? {
[Op.or]: [
{
id: {
[Op.in]: searchTerms.map((term) => Utils.uuid(term)),
},
},
{
name: {
[Op.or]: searchTerms.map((term) => ({
[Op.iLike]: `%${term}%`,
})),
},
},
],
}
: undefined,
},
...include,
];
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.roles.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('roles', 'name', query),
],
};
}
const records = await db.roles.findAll({
attributes: ['id', 'name'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};

View File

@ -0,0 +1,334 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Servicos_produtosDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const servicos_produtos = await db.servicos_produtos.create(
{
id: data.id || undefined,
nome_do_item: data.nome_do_item || null,
descricao: data.descricao || null,
preco_unitario: data.preco_unitario || null,
unidade: data.unidade || null,
categoria: data.categoria || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
return servicos_produtos;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const servicos_produtosData = data.map((item, index) => ({
id: item.id || undefined,
nome_do_item: item.nome_do_item || null,
descricao: item.descricao || null,
preco_unitario: item.preco_unitario || null,
unidade: item.unidade || null,
categoria: item.categoria || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const servicos_produtos = await db.servicos_produtos.bulkCreate(
servicos_produtosData,
{ transaction },
);
// For each item created, replace relation files
return servicos_produtos;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const servicos_produtos = await db.servicos_produtos.findByPk(
id,
{},
{ transaction },
);
const updatePayload = {};
if (data.nome_do_item !== undefined)
updatePayload.nome_do_item = data.nome_do_item;
if (data.descricao !== undefined) updatePayload.descricao = data.descricao;
if (data.preco_unitario !== undefined)
updatePayload.preco_unitario = data.preco_unitario;
if (data.unidade !== undefined) updatePayload.unidade = data.unidade;
if (data.categoria !== undefined) updatePayload.categoria = data.categoria;
updatePayload.updatedById = currentUser.id;
await servicos_produtos.update(updatePayload, { transaction });
return servicos_produtos;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const servicos_produtos = await db.servicos_produtos.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of servicos_produtos) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of servicos_produtos) {
await record.destroy({ transaction });
}
});
return servicos_produtos;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const servicos_produtos = await db.servicos_produtos.findByPk(id, options);
await servicos_produtos.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await servicos_produtos.destroy({
transaction,
});
return servicos_produtos;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const servicos_produtos = await db.servicos_produtos.findOne(
{ where },
{ transaction },
);
if (!servicos_produtos) {
return servicos_produtos;
}
const output = servicos_produtos.get({ plain: true });
output.itens_do_orcamento_servico_produto =
await servicos_produtos.getItens_do_orcamento_servico_produto({
transaction,
});
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.nome_do_item) {
where = {
...where,
[Op.and]: Utils.ilike(
'servicos_produtos',
'nome_do_item',
filter.nome_do_item,
),
};
}
if (filter.descricao) {
where = {
...where,
[Op.and]: Utils.ilike(
'servicos_produtos',
'descricao',
filter.descricao,
),
};
}
if (filter.unidade) {
where = {
...where,
[Op.and]: Utils.ilike('servicos_produtos', 'unidade', filter.unidade),
};
}
if (filter.preco_unitarioRange) {
const [start, end] = filter.preco_unitarioRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
preco_unitario: {
...where.preco_unitario,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
preco_unitario: {
...where.preco_unitario,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.categoria) {
where = {
...where,
categoria: filter.categoria,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.servicos_produtos.findAndCountAll(
queryOptions,
);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('servicos_produtos', 'nome_do_item', query),
],
};
}
const records = await db.servicos_produtos.findAll({
attributes: ['id', 'nome_do_item'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['nome_do_item', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.nome_do_item,
}));
}
};

743
backend/src/db/api/users.js Normal file
View File

@ -0,0 +1,743 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const bcrypt = require('bcrypt');
const config = require('../../config');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class UsersDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const users = await db.users.create(
{
id: data.data.id || undefined,
firstName: data.data.firstName || null,
lastName: data.data.lastName || null,
phoneNumber: data.data.phoneNumber || null,
email: data.data.email || null,
disabled: data.data.disabled || false,
password: data.data.password || null,
emailVerified: data.data.emailVerified || true,
emailVerificationToken: data.data.emailVerificationToken || null,
emailVerificationTokenExpiresAt:
data.data.emailVerificationTokenExpiresAt || null,
passwordResetToken: data.data.passwordResetToken || null,
passwordResetTokenExpiresAt:
data.data.passwordResetTokenExpiresAt || null,
provider: data.data.provider || null,
importHash: data.data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
if (!data.data.app_role) {
const role = await db.roles.findOne({
where: { name: 'User' },
});
if (role) {
await users.setApp_role(role, {
transaction,
});
}
} else {
await users.setApp_role(data.data.app_role || null, {
transaction,
});
}
await users.setCustom_permissions(data.data.custom_permissions || [], {
transaction,
});
await FileDBApi.replaceRelationFiles(
{
belongsTo: db.users.getTableName(),
belongsToColumn: 'avatar',
belongsToId: users.id,
},
data.data.avatar,
options,
);
return users;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const usersData = data.map((item, index) => ({
id: item.id || undefined,
firstName: item.firstName || null,
lastName: item.lastName || null,
phoneNumber: item.phoneNumber || null,
email: item.email || null,
disabled: item.disabled || false,
password: item.password || null,
emailVerified: item.emailVerified || false,
emailVerificationToken: item.emailVerificationToken || null,
emailVerificationTokenExpiresAt:
item.emailVerificationTokenExpiresAt || null,
passwordResetToken: item.passwordResetToken || null,
passwordResetTokenExpiresAt: item.passwordResetTokenExpiresAt || null,
provider: item.provider || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const users = await db.users.bulkCreate(usersData, { transaction });
// For each item created, replace relation files
for (let i = 0; i < users.length; i++) {
await FileDBApi.replaceRelationFiles(
{
belongsTo: db.users.getTableName(),
belongsToColumn: 'avatar',
belongsToId: users[i].id,
},
data[i].avatar,
options,
);
}
return users;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const users = await db.users.findByPk(id, {}, { transaction });
if (!data?.app_role) {
data.app_role = users?.app_role?.id;
}
if (!data?.custom_permissions) {
data.custom_permissions = users?.custom_permissions?.map(
(item) => item.id,
);
}
if (data.password) {
data.password = bcrypt.hashSync(data.password, config.bcrypt.saltRounds);
} else {
data.password = users.password;
}
const updatePayload = {};
if (data.firstName !== undefined) updatePayload.firstName = data.firstName;
if (data.lastName !== undefined) updatePayload.lastName = data.lastName;
if (data.phoneNumber !== undefined)
updatePayload.phoneNumber = data.phoneNumber;
if (data.email !== undefined) updatePayload.email = data.email;
if (data.disabled !== undefined) updatePayload.disabled = data.disabled;
if (data.password !== undefined) updatePayload.password = data.password;
if (data.emailVerified !== undefined)
updatePayload.emailVerified = data.emailVerified;
else updatePayload.emailVerified = true;
if (data.emailVerificationToken !== undefined)
updatePayload.emailVerificationToken = data.emailVerificationToken;
if (data.emailVerificationTokenExpiresAt !== undefined)
updatePayload.emailVerificationTokenExpiresAt =
data.emailVerificationTokenExpiresAt;
if (data.passwordResetToken !== undefined)
updatePayload.passwordResetToken = data.passwordResetToken;
if (data.passwordResetTokenExpiresAt !== undefined)
updatePayload.passwordResetTokenExpiresAt =
data.passwordResetTokenExpiresAt;
if (data.provider !== undefined) updatePayload.provider = data.provider;
updatePayload.updatedById = currentUser.id;
await users.update(updatePayload, { transaction });
if (data.app_role !== undefined) {
await users.setApp_role(
data.app_role,
{ transaction },
);
}
if (data.custom_permissions !== undefined) {
await users.setCustom_permissions(data.custom_permissions, {
transaction,
});
}
await FileDBApi.replaceRelationFiles(
{
belongsTo: db.users.getTableName(),
belongsToColumn: 'avatar',
belongsToId: users.id,
},
data.avatar,
options,
);
return users;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const users = await db.users.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of users) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of users) {
await record.destroy({ transaction });
}
});
return users;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const users = await db.users.findByPk(id, options);
await users.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await users.destroy({
transaction,
});
return users;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const users = await db.users.findOne({ where }, { transaction });
if (!users) {
return users;
}
const output = users.get({ plain: true });
output.avatar = await users.getAvatar({
transaction,
});
output.app_role = await users.getApp_role({
transaction,
});
if (output.app_role) {
output.app_role_permissions = await output.app_role.getPermissions({
transaction,
});
}
output.custom_permissions = await users.getCustom_permissions({
transaction,
});
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [
{
model: db.roles,
as: 'app_role',
where: filter.app_role
? {
[Op.or]: [
{
id: {
[Op.in]: filter.app_role
.split('|')
.map((term) => Utils.uuid(term)),
},
},
{
name: {
[Op.or]: filter.app_role
.split('|')
.map((term) => ({ [Op.iLike]: `%${term}%` })),
},
},
],
}
: {},
},
{
model: db.permissions,
as: 'custom_permissions',
required: false,
},
{
model: db.file,
as: 'avatar',
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.firstName) {
where = {
...where,
[Op.and]: Utils.ilike('users', 'firstName', filter.firstName),
};
}
if (filter.lastName) {
where = {
...where,
[Op.and]: Utils.ilike('users', 'lastName', filter.lastName),
};
}
if (filter.phoneNumber) {
where = {
...where,
[Op.and]: Utils.ilike('users', 'phoneNumber', filter.phoneNumber),
};
}
if (filter.email) {
where = {
...where,
[Op.and]: Utils.ilike('users', 'email', filter.email),
};
}
if (filter.password) {
where = {
...where,
[Op.and]: Utils.ilike('users', 'password', filter.password),
};
}
if (filter.emailVerificationToken) {
where = {
...where,
[Op.and]: Utils.ilike(
'users',
'emailVerificationToken',
filter.emailVerificationToken,
),
};
}
if (filter.passwordResetToken) {
where = {
...where,
[Op.and]: Utils.ilike(
'users',
'passwordResetToken',
filter.passwordResetToken,
),
};
}
if (filter.provider) {
where = {
...where,
[Op.and]: Utils.ilike('users', 'provider', filter.provider),
};
}
if (filter.emailVerificationTokenExpiresAtRange) {
const [start, end] = filter.emailVerificationTokenExpiresAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
emailVerificationTokenExpiresAt: {
...where.emailVerificationTokenExpiresAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
emailVerificationTokenExpiresAt: {
...where.emailVerificationTokenExpiresAt,
[Op.lte]: end,
},
};
}
}
if (filter.passwordResetTokenExpiresAtRange) {
const [start, end] = filter.passwordResetTokenExpiresAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
passwordResetTokenExpiresAt: {
...where.passwordResetTokenExpiresAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
passwordResetTokenExpiresAt: {
...where.passwordResetTokenExpiresAt,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.disabled) {
where = {
...where,
disabled: filter.disabled,
};
}
if (filter.emailVerified) {
where = {
...where,
emailVerified: filter.emailVerified,
};
}
if (filter.custom_permissions) {
const searchTerms = filter.custom_permissions.split('|');
include = [
{
model: db.permissions,
as: 'custom_permissions_filter',
required: searchTerms.length > 0,
where:
searchTerms.length > 0
? {
[Op.or]: [
{
id: {
[Op.in]: searchTerms.map((term) => Utils.uuid(term)),
},
},
{
name: {
[Op.or]: searchTerms.map((term) => ({
[Op.iLike]: `%${term}%`,
})),
},
},
],
}
: undefined,
},
...include,
];
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.users.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('users', 'firstName', query),
],
};
}
const records = await db.users.findAll({
attributes: ['id', 'firstName'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['firstName', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.firstName,
}));
}
static async createFromAuth(data, options) {
const transaction = (options && options.transaction) || undefined;
const users = await db.users.create(
{
email: data.email,
firstName: data.firstName,
authenticationUid: data.authenticationUid,
password: data.password,
},
{ transaction },
);
const app_role = await db.roles.findOne({
where: { name: config.roles?.user || 'User' },
});
if (app_role?.id) {
await users.setApp_role(app_role?.id || null, {
transaction,
});
}
await users.update(
{
authenticationUid: users.id,
},
{ transaction },
);
delete users.password;
return users;
}
static async updatePassword(id, password, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const users = await db.users.findByPk(id, {
transaction,
});
await users.update(
{
password,
authenticationUid: id,
updatedById: currentUser.id,
},
{ transaction },
);
return users;
}
static async generateEmailVerificationToken(email, options) {
return this._generateToken(
['emailVerificationToken', 'emailVerificationTokenExpiresAt'],
email,
options,
);
}
static async generatePasswordResetToken(email, options) {
return this._generateToken(
['passwordResetToken', 'passwordResetTokenExpiresAt'],
email,
options,
);
}
static async findByPasswordResetToken(token, options) {
const transaction = (options && options.transaction) || undefined;
return db.users.findOne(
{
where: {
passwordResetToken: token,
passwordResetTokenExpiresAt: {
[db.Sequelize.Op.gt]: Date.now(),
},
},
},
{ transaction },
);
}
static async findByEmailVerificationToken(token, options) {
const transaction = (options && options.transaction) || undefined;
return db.users.findOne(
{
where: {
emailVerificationToken: token,
emailVerificationTokenExpiresAt: {
[db.Sequelize.Op.gt]: Date.now(),
},
},
},
{ transaction },
);
}
static async markEmailVerified(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const users = await db.users.findByPk(id, {
transaction,
});
await users.update(
{
emailVerified: true,
updatedById: currentUser.id,
},
{ transaction },
);
return true;
}
static async _generateToken(keyNames, email, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const users = await db.users.findOne(
{
where: { email: email.toLowerCase() },
},
{
transaction,
},
);
const token = crypto.randomBytes(20).toString('hex');
const tokenExpiresAt = Date.now() + 360000;
if (users) {
await users.update(
{
[keyNames[0]]: token,
[keyNames[1]]: tokenExpiresAt,
updatedById: currentUser.id,
},
{ transaction },
);
}
return token;
}
};

View File

@ -0,0 +1,270 @@
const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class UsuariosDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const usuarios = await db.usuarios.create(
{
id: data.id || undefined,
nome: data.nome || null,
email: data.email || null,
senha: data.senha || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
return usuarios;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const usuariosData = data.map((item, index) => ({
id: item.id || undefined,
nome: item.nome || null,
email: item.email || null,
senha: item.senha || null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const usuarios = await db.usuarios.bulkCreate(usuariosData, {
transaction,
});
// For each item created, replace relation files
return usuarios;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const usuarios = await db.usuarios.findByPk(id, {}, { transaction });
const updatePayload = {};
if (data.nome !== undefined) updatePayload.nome = data.nome;
if (data.email !== undefined) updatePayload.email = data.email;
if (data.senha !== undefined) updatePayload.senha = data.senha;
updatePayload.updatedById = currentUser.id;
await usuarios.update(updatePayload, { transaction });
return usuarios;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const usuarios = await db.usuarios.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of usuarios) {
await record.update({ deletedBy: currentUser.id }, { transaction });
}
for (const record of usuarios) {
await record.destroy({ transaction });
}
});
return usuarios;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const usuarios = await db.usuarios.findByPk(id, options);
await usuarios.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await usuarios.destroy({
transaction,
});
return usuarios;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const usuarios = await db.usuarios.findOne({ where }, { transaction });
if (!usuarios) {
return usuarios;
}
const output = usuarios.get({ plain: true });
return output;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const orderBy = null;
const transaction = (options && options.transaction) || undefined;
let include = [];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
}
if (filter.nome) {
where = {
...where,
[Op.and]: Utils.ilike('usuarios', 'nome', filter.nome),
};
}
if (filter.email) {
where = {
...where,
[Op.and]: Utils.ilike('usuarios', 'email', filter.email),
};
}
if (filter.senha) {
where = {
...where,
[Op.and]: Utils.ilike('usuarios', 'senha', filter.senha),
};
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true',
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order:
filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log,
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.usuarios.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike('usuarios', 'nome', query),
],
};
}
const records = await db.usuarios.findAll({
attributes: ['id', 'nome'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['nome', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.nome,
}));
}
};

View File

@ -0,0 +1,31 @@
module.exports = {
production: {
dialect: 'postgres',
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
logging: console.log,
seederStorage: 'sequelize',
},
development: {
username: 'postgres',
dialect: 'postgres',
password: '',
database: 'db_sm_gestor',
host: process.env.DB_HOST || 'localhost',
logging: console.log,
seederStorage: 'sequelize',
},
dev_stage: {
dialect: 'postgres',
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
logging: console.log,
seederStorage: 'sequelize',
},
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const clientes = sequelize.define(
'clientes',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
nome_completo: {
type: DataTypes.TEXT,
},
telefone_principal: {
type: DataTypes.TEXT,
},
endereco: {
type: DataTypes.TEXT,
},
telefone_secundario: {
type: DataTypes.TEXT,
},
email: {
type: DataTypes.TEXT,
},
rg: {
type: DataTypes.TEXT,
},
cpf: {
type: DataTypes.TEXT,
},
estado_civil: {
type: DataTypes.TEXT,
},
profissao: {
type: DataTypes.TEXT,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
clientes.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
db.clientes.hasMany(db.orcamentos, {
as: 'orcamentos_cliente',
foreignKey: {
name: 'clienteId',
},
constraints: false,
});
//end loop
db.clientes.belongsTo(db.users, {
as: 'createdBy',
});
db.clientes.belongsTo(db.users, {
as: 'updatedBy',
});
};
return clientes;
};

View File

@ -0,0 +1,71 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const contas_a_pagar = sequelize.define(
'contas_a_pagar',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
descricao_da_despesa: {
type: DataTypes.TEXT,
},
data_de_vencimento: {
type: DataTypes.DATE,
},
valor: {
type: DataTypes.DECIMAL,
},
status: {
type: DataTypes.ENUM,
values: ['APagar', 'Pago', 'EmAtraso'],
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
contas_a_pagar.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
//end loop
db.contas_a_pagar.belongsTo(db.fornecedores, {
as: 'fornecedor',
foreignKey: {
name: 'fornecedorId',
},
constraints: false,
});
db.contas_a_pagar.belongsTo(db.users, {
as: 'createdBy',
});
db.contas_a_pagar.belongsTo(db.users, {
as: 'updatedBy',
});
};
return contas_a_pagar;
};

View File

@ -0,0 +1,71 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const contas_a_receber = sequelize.define(
'contas_a_receber',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
descricao_da_parcela: {
type: DataTypes.TEXT,
},
data_de_vencimento: {
type: DataTypes.DATE,
},
valor_da_parcela: {
type: DataTypes.DECIMAL,
},
status: {
type: DataTypes.ENUM,
values: ['AReceber', 'Recebido', 'EmAtraso'],
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
contas_a_receber.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
//end loop
db.contas_a_receber.belongsTo(db.orcamentos, {
as: 'orcamento',
foreignKey: {
name: 'orcamentoId',
},
constraints: false,
});
db.contas_a_receber.belongsTo(db.users, {
as: 'createdBy',
});
db.contas_a_receber.belongsTo(db.users, {
as: 'updatedBy',
});
};
return contas_a_receber;
};

View File

@ -0,0 +1,53 @@
module.exports = function (sequelize, DataTypes) {
const file = sequelize.define(
'file',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
belongsTo: DataTypes.STRING(255),
belongsToId: DataTypes.UUID,
belongsToColumn: DataTypes.STRING(255),
name: {
type: DataTypes.STRING(2083),
allowNull: false,
validate: {
notEmpty: true,
},
},
sizeInBytes: {
type: DataTypes.INTEGER,
allowNull: true,
},
privateUrl: {
type: DataTypes.STRING(2083),
allowNull: true,
},
publicUrl: {
type: DataTypes.STRING(2083),
allowNull: false,
validate: {
notEmpty: true,
},
},
},
{
timestamps: true,
paranoid: true,
},
);
file.associate = (db) => {
db.file.belongsTo(db.users, {
as: 'createdBy',
});
db.file.belongsTo(db.users, {
as: 'updatedBy',
});
};
return file;
};

View File

@ -0,0 +1,73 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const fornecedores = sequelize.define(
'fornecedores',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
nome_fornecedor: {
type: DataTypes.TEXT,
},
cnpj_cpf: {
type: DataTypes.TEXT,
},
contato_principal: {
type: DataTypes.TEXT,
},
telefone: {
type: DataTypes.TEXT,
},
email: {
type: DataTypes.TEXT,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
fornecedores.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
db.fornecedores.hasMany(db.contas_a_pagar, {
as: 'contas_a_pagar_fornecedor',
foreignKey: {
name: 'fornecedorId',
},
constraints: false,
});
//end loop
db.fornecedores.belongsTo(db.users, {
as: 'createdBy',
});
db.fornecedores.belongsTo(db.users, {
as: 'updatedBy',
});
};
return fornecedores;
};

View File

@ -0,0 +1,69 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const funcionarios = sequelize.define(
'funcionarios',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
nome_completo: {
type: DataTypes.TEXT,
},
cargo: {
type: DataTypes.TEXT,
},
telefone: {
type: DataTypes.TEXT,
},
email: {
type: DataTypes.TEXT,
},
endereco: {
type: DataTypes.TEXT,
},
descricao: {
type: DataTypes.TEXT,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
funcionarios.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
//end loop
db.funcionarios.belongsTo(db.users, {
as: 'createdBy',
});
db.funcionarios.belongsTo(db.users, {
as: 'updatedBy',
});
};
return funcionarios;
};

View File

@ -0,0 +1,47 @@
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require('../db.config')[env];
const db = {};
let sequelize;
console.log(env);
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(
config.database,
config.username,
config.password,
config,
);
}
fs.readdirSync(__dirname)
.filter((file) => {
return (
file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js'
);
})
.forEach((file) => {
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes,
);
db[model.name] = model;
});
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;

View File

@ -0,0 +1,69 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const itens_do_orcamento = sequelize.define(
'itens_do_orcamento',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
quantidade: {
type: DataTypes.INTEGER,
},
subtotal: {
type: DataTypes.DECIMAL,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
itens_do_orcamento.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
//end loop
db.itens_do_orcamento.belongsTo(db.orcamentos, {
as: 'orcamento',
foreignKey: {
name: 'orcamentoId',
},
constraints: false,
});
db.itens_do_orcamento.belongsTo(db.servicos_produtos, {
as: 'servico_produto',
foreignKey: {
name: 'servico_produtoId',
},
constraints: false,
});
db.itens_do_orcamento.belongsTo(db.users, {
as: 'createdBy',
});
db.itens_do_orcamento.belongsTo(db.users, {
as: 'updatedBy',
});
};
return itens_do_orcamento;
};

View File

@ -0,0 +1,113 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const orcamentos = sequelize.define(
'orcamentos',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
id_orcamento: {
type: DataTypes.TEXT,
},
data_do_evento: {
type: DataTypes.DATE,
},
local_do_evento: {
type: DataTypes.TEXT,
},
status: {
type: DataTypes.ENUM,
values: ['Pendente', 'Enviado', 'Aprovado', 'Recusado'],
},
tipo_desconto: {
type: DataTypes.ENUM,
values: ['Valor(R$)', 'Porcentagem(%)'],
},
valor_desconto: {
type: DataTypes.DECIMAL,
},
valor_entrada: {
type: DataTypes.DECIMAL,
},
forma_de_pagamento: {
type: DataTypes.TEXT,
},
quantidade_parcelas: {
type: DataTypes.INTEGER,
},
valor_total: {
type: DataTypes.DECIMAL,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
orcamentos.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
db.orcamentos.hasMany(db.contas_a_receber, {
as: 'contas_a_receber_orcamento',
foreignKey: {
name: 'orcamentoId',
},
constraints: false,
});
db.orcamentos.hasMany(db.itens_do_orcamento, {
as: 'itens_do_orcamento_orcamento',
foreignKey: {
name: 'orcamentoId',
},
constraints: false,
});
//end loop
db.orcamentos.belongsTo(db.clientes, {
as: 'cliente',
foreignKey: {
name: 'clienteId',
},
constraints: false,
});
db.orcamentos.belongsTo(db.users, {
as: 'createdBy',
});
db.orcamentos.belongsTo(db.users, {
as: 'updatedBy',
});
};
return orcamentos;
};

View File

@ -0,0 +1,49 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const permissions = sequelize.define(
'permissions',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
name: {
type: DataTypes.TEXT,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
permissions.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
//end loop
db.permissions.belongsTo(db.users, {
as: 'createdBy',
});
db.permissions.belongsTo(db.users, {
as: 'updatedBy',
});
};
return permissions;
};

View File

@ -0,0 +1,79 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const roles = sequelize.define(
'roles',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
name: {
type: DataTypes.TEXT,
},
role_customization: {
type: DataTypes.TEXT,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
roles.associate = (db) => {
db.roles.belongsToMany(db.permissions, {
as: 'permissions',
foreignKey: {
name: 'roles_permissionsId',
},
constraints: false,
through: 'rolesPermissionsPermissions',
});
db.roles.belongsToMany(db.permissions, {
as: 'permissions_filter',
foreignKey: {
name: 'roles_permissionsId',
},
constraints: false,
through: 'rolesPermissionsPermissions',
});
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
db.roles.hasMany(db.users, {
as: 'users_app_role',
foreignKey: {
name: 'app_roleId',
},
constraints: false,
});
//end loop
db.roles.belongsTo(db.users, {
as: 'createdBy',
});
db.roles.belongsTo(db.users, {
as: 'updatedBy',
});
};
return roles;
};

View File

@ -0,0 +1,89 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const servicos_produtos = sequelize.define(
'servicos_produtos',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
nome_do_item: {
type: DataTypes.TEXT,
},
descricao: {
type: DataTypes.TEXT,
},
preco_unitario: {
type: DataTypes.DECIMAL,
},
unidade: {
type: DataTypes.TEXT,
},
categoria: {
type: DataTypes.ENUM,
values: [
'Buffet',
'Decoração',
'Salgados',
'Bebidas',
'MãodeObra',
'Aluguel',
'Outros',
],
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
servicos_produtos.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
db.servicos_produtos.hasMany(db.itens_do_orcamento, {
as: 'itens_do_orcamento_servico_produto',
foreignKey: {
name: 'servico_produtoId',
},
constraints: false,
});
//end loop
db.servicos_produtos.belongsTo(db.users, {
as: 'createdBy',
});
db.servicos_produtos.belongsTo(db.users, {
as: 'updatedBy',
});
};
return servicos_produtos;
};

View File

@ -0,0 +1,171 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const users = sequelize.define(
'users',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
firstName: {
type: DataTypes.TEXT,
},
lastName: {
type: DataTypes.TEXT,
},
phoneNumber: {
type: DataTypes.TEXT,
},
email: {
type: DataTypes.TEXT,
},
disabled: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
password: {
type: DataTypes.TEXT,
},
emailVerified: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
emailVerificationToken: {
type: DataTypes.TEXT,
},
emailVerificationTokenExpiresAt: {
type: DataTypes.DATE,
},
passwordResetToken: {
type: DataTypes.TEXT,
},
passwordResetTokenExpiresAt: {
type: DataTypes.DATE,
},
provider: {
type: DataTypes.TEXT,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
users.associate = (db) => {
db.users.belongsToMany(db.permissions, {
as: 'custom_permissions',
foreignKey: {
name: 'users_custom_permissionsId',
},
constraints: false,
through: 'usersCustom_permissionsPermissions',
});
db.users.belongsToMany(db.permissions, {
as: 'custom_permissions_filter',
foreignKey: {
name: 'users_custom_permissionsId',
},
constraints: false,
through: 'usersCustom_permissionsPermissions',
});
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
//end loop
db.users.belongsTo(db.roles, {
as: 'app_role',
foreignKey: {
name: 'app_roleId',
},
constraints: false,
});
db.users.hasMany(db.file, {
as: 'avatar',
foreignKey: 'belongsToId',
constraints: false,
scope: {
belongsTo: db.users.getTableName(),
belongsToColumn: 'avatar',
},
});
db.users.belongsTo(db.users, {
as: 'createdBy',
});
db.users.belongsTo(db.users, {
as: 'updatedBy',
});
};
users.beforeCreate((users, options) => {
users = trimStringFields(users);
if (
users.provider !== providers.LOCAL &&
Object.values(providers).indexOf(users.provider) > -1
) {
users.emailVerified = true;
if (!users.password) {
const password = crypto.randomBytes(20).toString('hex');
const hashedPassword = bcrypt.hashSync(
password,
config.bcrypt.saltRounds,
);
users.password = hashedPassword;
}
}
});
users.beforeUpdate((users, options) => {
users = trimStringFields(users);
});
return users;
};
function trimStringFields(users) {
users.email = users.email.trim();
users.firstName = users.firstName ? users.firstName.trim() : null;
users.lastName = users.lastName ? users.lastName.trim() : null;
return users;
}

View File

@ -0,0 +1,57 @@
const config = require('../../config');
const providers = config.providers;
const crypto = require('crypto');
const bcrypt = require('bcrypt');
const moment = require('moment');
module.exports = function (sequelize, DataTypes) {
const usuarios = sequelize.define(
'usuarios',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
nome: {
type: DataTypes.TEXT,
},
email: {
type: DataTypes.TEXT,
},
senha: {
type: DataTypes.TEXT,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
},
);
usuarios.associate = (db) => {
/// loop through entities and it's fields, and if ref === current e[name] and create relation has many on parent entity
//end loop
db.usuarios.belongsTo(db.users, {
as: 'createdBy',
});
db.usuarios.belongsTo(db.users, {
as: 'updatedBy',
});
};
return usuarios;
};

16
backend/src/db/reset.js Normal file
View File

@ -0,0 +1,16 @@
const db = require('./models');
const { execSync } = require('child_process');
console.log('Resetting Database');
db.sequelize
.sync({ force: true })
.then(() => {
execSync('sequelize db:seed:all');
console.log('OK');
process.exit();
})
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@ -0,0 +1,73 @@
'use strict';
const bcrypt = require('bcrypt');
const config = require('../../config');
const ids = [
'193bf4b5-9f07-4bd5-9a43-e7e41f3e96af',
'af5a87be-8f9c-4630-902a-37a60b7005ba',
'5bc531ab-611f-41f3-9373-b7cc5d09c93d',
];
module.exports = {
up: async (queryInterface, Sequelize) => {
let admin_hash = bcrypt.hashSync(
config.admin_pass,
config.bcrypt.saltRounds,
);
let user_hash = bcrypt.hashSync(config.user_pass, config.bcrypt.saltRounds);
try {
await queryInterface.bulkInsert('users', [
{
id: ids[0],
firstName: 'Admin',
email: config.admin_email,
emailVerified: true,
provider: config.providers.LOCAL,
password: admin_hash,
createdAt: new Date(),
updatedAt: new Date(),
},
{
id: ids[1],
firstName: 'John',
email: 'john@doe.com',
emailVerified: true,
provider: config.providers.LOCAL,
password: user_hash,
createdAt: new Date(),
updatedAt: new Date(),
},
{
id: ids[2],
firstName: 'Client',
email: 'client@hello.com',
emailVerified: true,
provider: config.providers.LOCAL,
password: user_hash,
createdAt: new Date(),
updatedAt: new Date(),
},
]);
} catch (error) {
console.error('Error during bulkInsert:', error);
throw error;
}
},
down: async (queryInterface, Sequelize) => {
try {
await queryInterface.bulkDelete(
'users',
{
id: {
[Sequelize.Op.in]: ids,
},
},
{},
);
} catch (error) {
console.error('Error during bulkDelete:', error);
throw error;
}
},
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

24
backend/src/db/utils.js Normal file
View File

@ -0,0 +1,24 @@
const validator = require('validator');
const { v4: uuid } = require('uuid');
const Sequelize = require('./models').Sequelize;
module.exports = class Utils {
static uuid(value) {
let id = value;
if (!validator.isUUID(id)) {
id = uuid();
}
return id;
}
static ilike(model, column, value) {
return Sequelize.where(
Sequelize.fn('lower', Sequelize.col(`${model}.${column}`)),
{
[Sequelize.Op.like]: `%${value}%`.toLowerCase(),
},
);
}
};

23
backend/src/helpers.js Normal file
View File

@ -0,0 +1,23 @@
const jwt = require('jsonwebtoken');
const config = require('./config');
module.exports = class Helpers {
static wrapAsync(fn) {
return function (req, res, next) {
fn(req, res, next).catch(next);
};
}
static commonErrorHandler(error, req, res, next) {
if ([400, 403, 404].includes(error.code)) {
return res.status(error.code).send(error.message);
}
console.error(error);
return res.status(500).send(error.message);
}
static jwtSign(data) {
return jwt.sign(data, config.secret_key, { expiresIn: '6h' });
}
};

211
backend/src/index.js Normal file
View File

@ -0,0 +1,211 @@
const express = require('express');
const cors = require('cors');
const app = express();
const passport = require('passport');
const path = require('path');
const fs = require('fs');
const bodyParser = require('body-parser');
const db = require('./db/models');
const config = require('./config');
const swaggerUI = require('swagger-ui-express');
const swaggerJsDoc = require('swagger-jsdoc');
const authRoutes = require('./routes/auth');
const fileRoutes = require('./routes/file');
const searchRoutes = require('./routes/search');
const pexelsRoutes = require('./routes/pexels');
const openaiRoutes = require('./routes/openai');
const usersRoutes = require('./routes/users');
const clientesRoutes = require('./routes/clientes');
const contas_a_pagarRoutes = require('./routes/contas_a_pagar');
const contas_a_receberRoutes = require('./routes/contas_a_receber');
const fornecedoresRoutes = require('./routes/fornecedores');
const funcionariosRoutes = require('./routes/funcionarios');
const itens_do_orcamentoRoutes = require('./routes/itens_do_orcamento');
const orcamentosRoutes = require('./routes/orcamentos');
const servicos_produtosRoutes = require('./routes/servicos_produtos');
const usuariosRoutes = require('./routes/usuarios');
const rolesRoutes = require('./routes/roles');
const permissionsRoutes = require('./routes/permissions');
const getBaseUrl = (url) => {
if (!url) return '';
return url.endsWith('/api') ? url.slice(0, -4) : url;
};
const options = {
definition: {
openapi: '3.0.0',
info: {
version: '1.0.0',
title: 'SM Gestor',
description:
'SM Gestor Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.',
},
servers: [
{
url: getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || config.swaggerUrl,
description: 'Development server',
},
],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
},
responses: {
UnauthorizedError: {
description: 'Access token is missing or invalid',
},
},
},
security: [
{
bearerAuth: [],
},
],
},
apis: ['./src/routes/*.js'],
};
const specs = swaggerJsDoc(options);
app.use(
'/api-docs',
function (req, res, next) {
swaggerUI.host =
getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || req.get('host');
next();
},
swaggerUI.serve,
swaggerUI.setup(specs),
);
app.use(cors({ origin: true }));
require('./auth/auth');
app.use(bodyParser.json());
app.use('/api/auth', authRoutes);
app.use('/api/file', fileRoutes);
app.use('/api/pexels', pexelsRoutes);
app.enable('trust proxy');
app.use(
'/api/users',
passport.authenticate('jwt', { session: false }),
usersRoutes,
);
app.use(
'/api/clientes',
passport.authenticate('jwt', { session: false }),
clientesRoutes,
);
app.use(
'/api/contas_a_pagar',
passport.authenticate('jwt', { session: false }),
contas_a_pagarRoutes,
);
app.use(
'/api/contas_a_receber',
passport.authenticate('jwt', { session: false }),
contas_a_receberRoutes,
);
app.use(
'/api/fornecedores',
passport.authenticate('jwt', { session: false }),
fornecedoresRoutes,
);
app.use(
'/api/funcionarios',
passport.authenticate('jwt', { session: false }),
funcionariosRoutes,
);
app.use(
'/api/itens_do_orcamento',
passport.authenticate('jwt', { session: false }),
itens_do_orcamentoRoutes,
);
app.use(
'/api/orcamentos',
passport.authenticate('jwt', { session: false }),
orcamentosRoutes,
);
app.use(
'/api/servicos_produtos',
passport.authenticate('jwt', { session: false }),
servicos_produtosRoutes,
);
app.use(
'/api/usuarios',
passport.authenticate('jwt', { session: false }),
usuariosRoutes,
);
app.use(
'/api/roles',
passport.authenticate('jwt', { session: false }),
rolesRoutes,
);
app.use(
'/api/permissions',
passport.authenticate('jwt', { session: false }),
permissionsRoutes,
);
app.use(
'/api/openai',
passport.authenticate('jwt', { session: false }),
openaiRoutes,
);
app.use(
'/api/search',
passport.authenticate('jwt', { session: false }),
searchRoutes,
);
const publicDir = path.join(__dirname, '../public');
if (fs.existsSync(publicDir)) {
app.use('/', express.static(publicDir));
app.get('*', function (request, response) {
response.sendFile(path.resolve(publicDir, 'index.html'));
});
}
const PORT = process.env.NODE_ENV === 'dev_stage' ? 3000 : 8080;
db.sequelize.sync().then(function () {
app.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});
});
module.exports = app;

View File

@ -0,0 +1,176 @@
const ValidationError = require('../services/notifications/errors/validation');
const RolesDBApi = require('../db/api/roles');
// Cache for the 'Public' role object
let publicRoleCache = null;
// Function to asynchronously fetch and cache the 'Public' role
async function fetchAndCachePublicRole() {
try {
// Use RolesDBApi to find the role by name 'Public'
publicRoleCache = await RolesDBApi.findBy({ name: 'Public' });
if (!publicRoleCache) {
console.error(
"WARNING: Role 'Public' not found in database during middleware startup. Check your migrations.",
);
// The system might not function correctly without this role. May need to throw an error or use a fallback stub.
} else {
console.log("'Public' role successfully loaded and cached.");
}
} catch (error) {
console.error(
"Error fetching 'Public' role during middleware startup:",
error,
);
// Handle the error during startup fetch
throw error; // Important to know if the app can proceed without the Public role
}
}
// Trigger the role fetching when the check-permissions.js module is imported/loaded
// This should happen during application startup when routes are being configured.
fetchAndCachePublicRole().catch((error) => {
// Handle the case where the fetchAndCachePublicRole promise is rejected
console.error(
'Critical error during permissions middleware initialization:',
error,
);
// Decide here if the process should exit if the Public role is essential.
// process.exit(1);
});
/**
* Middleware creator to check if the current user (or Public role) has a specific permission.
* @param {string} permission - The name of the required permission.
* @return {import("express").RequestHandler} Express middleware function.
*/
function checkPermissions(permission) {
return async (req, res, next) => {
const { currentUser } = req;
// 1. Check self-access bypass (only if the user is authenticated)
if (
currentUser &&
(currentUser.id === req.params.id || currentUser.id === req.body.id)
) {
return next(); // User has access to their own resource
}
// 2. Check Custom Permissions (only if the user is authenticated)
if (currentUser) {
// Ensure custom_permissions is an array before using find
const customPermissions = Array.isArray(currentUser.custom_permissions)
? currentUser.custom_permissions
: [];
const userPermission = customPermissions.find(
(cp) => cp.name === permission,
);
if (userPermission) {
return next(); // User has a custom permission
}
}
// 3. Determine the "effective" role for permission check
let effectiveRole = null;
try {
if (currentUser && currentUser.app_role) {
// User is authenticated and has an assigned role
effectiveRole = currentUser.app_role;
} else {
// User is NOT authenticated OR is authenticated but has no role
// Use the cached 'Public' role
if (!publicRoleCache) {
// If the cache is unexpectedly empty (e.g., startup error caught),
// we can try fetching the role again synchronously (less ideal) or just deny access.
console.error(
'Public role cache is empty. Attempting synchronous fetch...',
);
// Less efficient fallback option:
effectiveRole = await RolesDBApi.findBy({ name: 'Public' }); // Could be slow
if (!effectiveRole) {
// If even the synchronous attempt failed
return next(
new Error(
'Internal Server Error: Public role missing and cannot be fetched.',
),
);
}
} else {
effectiveRole = publicRoleCache; // Use the cached object
}
}
// Check if we got a valid role object
if (!effectiveRole) {
return next(
new Error(
'Internal Server Error: Could not determine effective role.',
),
);
}
// 4. Check Permissions on the "effective" role
// Assume the effectiveRole object (from app_role or RolesDBApi) has a getPermissions() method
// or a 'permissions' property (if permissions are eagerly loaded).
let rolePermissions = [];
if (typeof effectiveRole.getPermissions === 'function') {
rolePermissions = await effectiveRole.getPermissions(); // Get permissions asynchronously if the method exists
} else if (Array.isArray(effectiveRole.permissions)) {
rolePermissions = effectiveRole.permissions; // Or take from property if permissions are pre-loaded
} else {
console.error(
'Role object lacks getPermissions() method or permissions property:',
effectiveRole,
);
return next(
new Error('Internal Server Error: Invalid role object format.'),
);
}
if (rolePermissions.find((p) => p.name === permission)) {
next(); // The "effective" role has the required permission
} else {
// The "effective" role does not have the required permission
const roleName = effectiveRole.name || 'unknown role';
next(
new ValidationError(
'auth.forbidden',
`Role '${roleName}' denied access to '${permission}'.`,
),
);
}
} catch (e) {
// Handle errors during role or permission fetching
console.error('Error during permission check:', e);
next(e); // Pass the error to the next middleware
}
};
}
const METHOD_MAP = {
POST: 'CREATE',
GET: 'READ',
PUT: 'UPDATE',
PATCH: 'UPDATE',
DELETE: 'DELETE',
};
/**
* Middleware creator to check standard CRUD permissions based on HTTP method and entity name.
* @param {string} name - The name of the entity.
* @return {import("express").RequestHandler} Express middleware function.
*/
function checkCrudPermissions(name) {
return (req, res, next) => {
// Dynamically determine the permission name (e.g., 'READ_USERS')
const permissionName = `${METHOD_MAP[req.method]}_${name.toUpperCase()}`;
// Call the checkPermissions middleware with the determined permission
checkPermissions(permissionName)(req, res, next);
};
}
module.exports = {
checkPermissions,
checkCrudPermissions,
};

View File

@ -0,0 +1,11 @@
const util = require('util');
const Multer = require('multer');
const maxSize = 10 * 1024 * 1024;
let processFile = Multer({
storage: Multer.memoryStorage(),
limits: { fileSize: maxSize },
}).single('file');
let processFileMiddleware = util.promisify(processFile);
module.exports = processFileMiddleware;

268
backend/src/routes/auth.js Normal file
View File

@ -0,0 +1,268 @@
const express = require('express');
const passport = require('passport');
const config = require('../config');
const AuthService = require('../services/auth');
const ForbiddenError = require('../services/notifications/errors/forbidden');
const EmailSender = require('../services/email');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
/**
* @swagger
* components:
* schemas:
* Auth:
* type: object
* required:
* - email
* - password
* properties:
* email:
* type: string
* default: admin@flatlogic.com
* description: User email
* password:
* type: string
* default: password
* description: User password
*/
/**
* @swagger
* tags:
* name: Auth
* description: Authorization operations
*/
/**
* @swagger
* /api/auth/signin/local:
* post:
* tags: [Auth]
* summary: Logs user into the system
* description: Logs user into the system
* requestBody:
* description: Set valid user email and password
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Auth"
* responses:
* 200:
* description: Successful login
* 400:
* description: Invalid username/password supplied
* x-codegen-request-body-name: body
*/
router.post(
'/signin/local',
wrapAsync(async (req, res) => {
const payload = await AuthService.signin(
req.body.email,
req.body.password,
req,
);
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/auth/me:
* get:
* security:
* - bearerAuth: []
* tags: [Auth]
* summary: Get current authorized user info
* description: Get current authorized user info
* responses:
* 200:
* description: Successful retrieval of current authorized user data
* 400:
* description: Invalid username/password supplied
* x-codegen-request-body-name: body
*/
router.get(
'/me',
passport.authenticate('jwt', { session: false }),
(req, res) => {
if (!req.currentUser || !req.currentUser.id) {
throw new ForbiddenError();
}
const payload = req.currentUser;
delete payload.password;
res.status(200).send(payload);
},
);
router.put(
'/password-reset',
wrapAsync(async (req, res) => {
const payload = await AuthService.passwordReset(
req.body.token,
req.body.password,
req,
);
res.status(200).send(payload);
}),
);
router.put(
'/password-update',
passport.authenticate('jwt', { session: false }),
wrapAsync(async (req, res) => {
const payload = await AuthService.passwordUpdate(
req.body.currentPassword,
req.body.newPassword,
req,
);
res.status(200).send(payload);
}),
);
router.post(
'/send-email-address-verification-email',
passport.authenticate('jwt', { session: false }),
wrapAsync(async (req, res) => {
if (!req.currentUser) {
throw new ForbiddenError();
}
await AuthService.sendEmailAddressVerificationEmail(req.currentUser.email);
const payload = true;
res.status(200).send(payload);
}),
);
router.post(
'/send-password-reset-email',
wrapAsync(async (req, res) => {
const link = new URL(req.headers.referer);
await AuthService.sendPasswordResetEmail(
req.body.email,
'register',
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/auth/signup:
* post:
* tags: [Auth]
* summary: Register new user into the system
* description: Register new user into the system
* requestBody:
* description: Set valid user email and password
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Auth"
* responses:
* 200:
* description: New user successfully signed up
* 400:
* description: Invalid username/password supplied
* 500:
* description: Some server error
* x-codegen-request-body-name: body
*/
router.post(
'/signup',
wrapAsync(async (req, res) => {
const link = new URL(req.headers.referer);
const payload = await AuthService.signup(
req.body.email,
req.body.password,
req,
link.host,
);
res.status(200).send(payload);
}),
);
router.put(
'/profile',
passport.authenticate('jwt', { session: false }),
wrapAsync(async (req, res) => {
if (!req.currentUser || !req.currentUser.id) {
throw new ForbiddenError();
}
await AuthService.updateProfile(req.body.profile, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
router.put(
'/verify-email',
wrapAsync(async (req, res) => {
const payload = await AuthService.verifyEmail(
req.body.token,
req,
req.headers.referer,
);
res.status(200).send(payload);
}),
);
router.get('/email-configured', (req, res) => {
const payload = EmailSender.isConfigured;
res.status(200).send(payload);
});
router.get('/signin/google', (req, res, next) => {
passport.authenticate('google', {
scope: ['profile', 'email'],
state: req.query.app,
})(req, res, next);
});
router.get(
'/signin/google/callback',
passport.authenticate('google', {
failureRedirect: '/login',
session: false,
}),
function (req, res) {
socialRedirect(res, req.query.state, req.user.token, config);
},
);
router.get('/signin/microsoft', (req, res, next) => {
passport.authenticate('microsoft', {
scope: ['https://graph.microsoft.com/user.read openid'],
state: req.query.app,
})(req, res, next);
});
router.get(
'/signin/microsoft/callback',
passport.authenticate('microsoft', {
failureRedirect: '/login',
session: false,
}),
function (req, res) {
socialRedirect(res, req.query.state, req.user.token, config);
},
);
router.use('/', require('../helpers').commonErrorHandler);
function socialRedirect(res, state, token, config) {
res.redirect(config.uiUrl + '/login?token=' + token);
}
module.exports = router;

View File

@ -0,0 +1,473 @@
const express = require('express');
const ClientesService = require('../services/clientes');
const ClientesDBApi = require('../db/api/clientes');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('clientes'));
/**
* @swagger
* components:
* schemas:
* Clientes:
* type: object
* properties:
* nome_completo:
* type: string
* default: nome_completo
* telefone_principal:
* type: string
* default: telefone_principal
* endereco:
* type: string
* default: endereco
* telefone_secundario:
* type: string
* default: telefone_secundario
* email:
* type: string
* default: email
* rg:
* type: string
* default: rg
* cpf:
* type: string
* default: cpf
* estado_civil:
* type: string
* default: estado_civil
* profissao:
* type: string
* default: profissao
*/
/**
* @swagger
* tags:
* name: Clientes
* description: The Clientes managing API
*/
/**
* @swagger
* /api/clientes:
* post:
* security:
* - bearerAuth: []
* tags: [Clientes]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Clientes"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Clientes"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await ClientesService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Clientes]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Clientes"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Clientes"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await ClientesService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/clientes/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Clientes]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Clientes"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Clientes"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await ClientesService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/clientes/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Clientes]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Clientes"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await ClientesService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/clientes/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Clientes]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Clientes"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await ClientesService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/clientes:
* get:
* security:
* - bearerAuth: []
* tags: [Clientes]
* summary: Get all clientes
* description: Get all clientes
* responses:
* 200:
* description: Clientes list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Clientes"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await ClientesDBApi.findAll(req.query, { currentUser });
if (filetype && filetype === 'csv') {
const fields = [
'id',
'nome_completo',
'telefone_principal',
'endereco',
'telefone_secundario',
'email',
'rg',
'cpf',
'estado_civil',
'profissao',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/clientes/count:
* get:
* security:
* - bearerAuth: []
* tags: [Clientes]
* summary: Count all clientes
* description: Count all clientes
* responses:
* 200:
* description: Clientes count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Clientes"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await ClientesDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/clientes/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Clientes]
* summary: Find all clientes that match search criteria
* description: Find all clientes that match search criteria
* responses:
* 200:
* description: Clientes list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Clientes"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await ClientesDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/clientes/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Clientes]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Clientes"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await ClientesDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

View File

@ -0,0 +1,455 @@
const express = require('express');
const Contas_a_pagarService = require('../services/contas_a_pagar');
const Contas_a_pagarDBApi = require('../db/api/contas_a_pagar');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('contas_a_pagar'));
/**
* @swagger
* components:
* schemas:
* Contas_a_pagar:
* type: object
* properties:
* descricao_da_despesa:
* type: string
* default: descricao_da_despesa
* valor:
* type: integer
* format: int64
*
*/
/**
* @swagger
* tags:
* name: Contas_a_pagar
* description: The Contas_a_pagar managing API
*/
/**
* @swagger
* /api/contas_a_pagar:
* post:
* security:
* - bearerAuth: []
* tags: [Contas_a_pagar]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Contas_a_pagar"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_pagar"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Contas_a_pagarService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Contas_a_pagar]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Contas_a_pagar"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_pagar"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Contas_a_pagarService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_pagar/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Contas_a_pagar]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Contas_a_pagar"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_pagar"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await Contas_a_pagarService.update(
req.body.data,
req.body.id,
req.currentUser,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_pagar/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Contas_a_pagar]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_pagar"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await Contas_a_pagarService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_pagar/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Contas_a_pagar]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_pagar"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await Contas_a_pagarService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_pagar:
* get:
* security:
* - bearerAuth: []
* tags: [Contas_a_pagar]
* summary: Get all contas_a_pagar
* description: Get all contas_a_pagar
* responses:
* 200:
* description: Contas_a_pagar list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Contas_a_pagar"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await Contas_a_pagarDBApi.findAll(req.query, {
currentUser,
});
if (filetype && filetype === 'csv') {
const fields = [
'id',
'descricao_da_despesa',
'valor',
'data_de_vencimento',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/contas_a_pagar/count:
* get:
* security:
* - bearerAuth: []
* tags: [Contas_a_pagar]
* summary: Count all contas_a_pagar
* description: Count all contas_a_pagar
* responses:
* 200:
* description: Contas_a_pagar count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Contas_a_pagar"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Contas_a_pagarDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_pagar/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Contas_a_pagar]
* summary: Find all contas_a_pagar that match search criteria
* description: Find all contas_a_pagar that match search criteria
* responses:
* 200:
* description: Contas_a_pagar list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Contas_a_pagar"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Contas_a_pagarDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/contas_a_pagar/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Contas_a_pagar]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_pagar"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await Contas_a_pagarDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,455 @@
const express = require('express');
const Contas_a_receberService = require('../services/contas_a_receber');
const Contas_a_receberDBApi = require('../db/api/contas_a_receber');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('contas_a_receber'));
/**
* @swagger
* components:
* schemas:
* Contas_a_receber:
* type: object
* properties:
* descricao_da_parcela:
* type: string
* default: descricao_da_parcela
* valor_da_parcela:
* type: integer
* format: int64
*
*/
/**
* @swagger
* tags:
* name: Contas_a_receber
* description: The Contas_a_receber managing API
*/
/**
* @swagger
* /api/contas_a_receber:
* post:
* security:
* - bearerAuth: []
* tags: [Contas_a_receber]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Contas_a_receber"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_receber"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Contas_a_receberService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Contas_a_receber]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Contas_a_receber"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_receber"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Contas_a_receberService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_receber/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Contas_a_receber]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Contas_a_receber"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_receber"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await Contas_a_receberService.update(
req.body.data,
req.body.id,
req.currentUser,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_receber/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Contas_a_receber]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_receber"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await Contas_a_receberService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_receber/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Contas_a_receber]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_receber"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await Contas_a_receberService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_receber:
* get:
* security:
* - bearerAuth: []
* tags: [Contas_a_receber]
* summary: Get all contas_a_receber
* description: Get all contas_a_receber
* responses:
* 200:
* description: Contas_a_receber list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Contas_a_receber"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await Contas_a_receberDBApi.findAll(req.query, {
currentUser,
});
if (filetype && filetype === 'csv') {
const fields = [
'id',
'descricao_da_parcela',
'valor_da_parcela',
'data_de_vencimento',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/contas_a_receber/count:
* get:
* security:
* - bearerAuth: []
* tags: [Contas_a_receber]
* summary: Count all contas_a_receber
* description: Count all contas_a_receber
* responses:
* 200:
* description: Contas_a_receber count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Contas_a_receber"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Contas_a_receberDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/contas_a_receber/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Contas_a_receber]
* summary: Find all contas_a_receber that match search criteria
* description: Find all contas_a_receber that match search criteria
* responses:
* 200:
* description: Contas_a_receber list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Contas_a_receber"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Contas_a_receberDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/contas_a_receber/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Contas_a_receber]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Contas_a_receber"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await Contas_a_receberDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,40 @@
const express = require('express');
const config = require('../config');
const path = require('path');
const passport = require('passport');
const services = require('../services/file');
const router = express.Router();
router.get('/download', (req, res) => {
if (
process.env.NODE_ENV == 'production' ||
process.env.NEXT_PUBLIC_BACK_API
) {
services.downloadGCloud(req, res);
} else {
services.downloadLocal(req, res);
}
});
router.post(
'/upload/:table/:field',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const fileName = `${req.params.table}/${req.params.field}`;
if (
process.env.NODE_ENV == 'production' ||
process.env.NEXT_PUBLIC_BACK_API
) {
services.uploadGCloud(fileName, req, res);
} else {
services.uploadLocal(fileName, {
entity: null,
maxFileSize: 10 * 1024 * 1024,
folderIncludesAuthenticationUid: false,
})(req, res);
}
},
);
module.exports = router;

View File

@ -0,0 +1,461 @@
const express = require('express');
const FornecedoresService = require('../services/fornecedores');
const FornecedoresDBApi = require('../db/api/fornecedores');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('fornecedores'));
/**
* @swagger
* components:
* schemas:
* Fornecedores:
* type: object
* properties:
* nome_fornecedor:
* type: string
* default: nome_fornecedor
* cnpj_cpf:
* type: string
* default: cnpj_cpf
* contato_principal:
* type: string
* default: contato_principal
* telefone:
* type: string
* default: telefone
* email:
* type: string
* default: email
*/
/**
* @swagger
* tags:
* name: Fornecedores
* description: The Fornecedores managing API
*/
/**
* @swagger
* /api/fornecedores:
* post:
* security:
* - bearerAuth: []
* tags: [Fornecedores]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Fornecedores"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Fornecedores"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await FornecedoresService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Fornecedores]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Fornecedores"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Fornecedores"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await FornecedoresService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/fornecedores/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Fornecedores]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Fornecedores"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Fornecedores"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await FornecedoresService.update(
req.body.data,
req.body.id,
req.currentUser,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/fornecedores/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Fornecedores]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Fornecedores"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await FornecedoresService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/fornecedores/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Fornecedores]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Fornecedores"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await FornecedoresService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/fornecedores:
* get:
* security:
* - bearerAuth: []
* tags: [Fornecedores]
* summary: Get all fornecedores
* description: Get all fornecedores
* responses:
* 200:
* description: Fornecedores list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Fornecedores"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await FornecedoresDBApi.findAll(req.query, { currentUser });
if (filetype && filetype === 'csv') {
const fields = [
'id',
'nome_fornecedor',
'cnpj_cpf',
'contato_principal',
'telefone',
'email',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/fornecedores/count:
* get:
* security:
* - bearerAuth: []
* tags: [Fornecedores]
* summary: Count all fornecedores
* description: Count all fornecedores
* responses:
* 200:
* description: Fornecedores count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Fornecedores"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await FornecedoresDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/fornecedores/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Fornecedores]
* summary: Find all fornecedores that match search criteria
* description: Find all fornecedores that match search criteria
* responses:
* 200:
* description: Fornecedores list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Fornecedores"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await FornecedoresDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/fornecedores/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Fornecedores]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Fornecedores"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await FornecedoresDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,465 @@
const express = require('express');
const FuncionariosService = require('../services/funcionarios');
const FuncionariosDBApi = require('../db/api/funcionarios');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('funcionarios'));
/**
* @swagger
* components:
* schemas:
* Funcionarios:
* type: object
* properties:
* nome_completo:
* type: string
* default: nome_completo
* cargo:
* type: string
* default: cargo
* telefone:
* type: string
* default: telefone
* email:
* type: string
* default: email
* endereco:
* type: string
* default: endereco
* descricao:
* type: string
* default: descricao
*/
/**
* @swagger
* tags:
* name: Funcionarios
* description: The Funcionarios managing API
*/
/**
* @swagger
* /api/funcionarios:
* post:
* security:
* - bearerAuth: []
* tags: [Funcionarios]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Funcionarios"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Funcionarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await FuncionariosService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Funcionarios]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Funcionarios"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Funcionarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await FuncionariosService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/funcionarios/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Funcionarios]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Funcionarios"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Funcionarios"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await FuncionariosService.update(
req.body.data,
req.body.id,
req.currentUser,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/funcionarios/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Funcionarios]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Funcionarios"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await FuncionariosService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/funcionarios/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Funcionarios]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Funcionarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await FuncionariosService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/funcionarios:
* get:
* security:
* - bearerAuth: []
* tags: [Funcionarios]
* summary: Get all funcionarios
* description: Get all funcionarios
* responses:
* 200:
* description: Funcionarios list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Funcionarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await FuncionariosDBApi.findAll(req.query, { currentUser });
if (filetype && filetype === 'csv') {
const fields = [
'id',
'nome_completo',
'cargo',
'telefone',
'email',
'endereco',
'descricao',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/funcionarios/count:
* get:
* security:
* - bearerAuth: []
* tags: [Funcionarios]
* summary: Count all funcionarios
* description: Count all funcionarios
* responses:
* 200:
* description: Funcionarios count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Funcionarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await FuncionariosDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/funcionarios/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Funcionarios]
* summary: Find all funcionarios that match search criteria
* description: Find all funcionarios that match search criteria
* responses:
* 200:
* description: Funcionarios list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Funcionarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await FuncionariosDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/funcionarios/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Funcionarios]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Funcionarios"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await FuncionariosDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,448 @@
const express = require('express');
const Itens_do_orcamentoService = require('../services/itens_do_orcamento');
const Itens_do_orcamentoDBApi = require('../db/api/itens_do_orcamento');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('itens_do_orcamento'));
/**
* @swagger
* components:
* schemas:
* Itens_do_orcamento:
* type: object
* properties:
* quantidade:
* type: integer
* format: int64
* subtotal:
* type: integer
* format: int64
*/
/**
* @swagger
* tags:
* name: Itens_do_orcamento
* description: The Itens_do_orcamento managing API
*/
/**
* @swagger
* /api/itens_do_orcamento:
* post:
* security:
* - bearerAuth: []
* tags: [Itens_do_orcamento]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Itens_do_orcamento"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Itens_do_orcamento"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Itens_do_orcamentoService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Itens_do_orcamento]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Itens_do_orcamento"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Itens_do_orcamento"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Itens_do_orcamentoService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/itens_do_orcamento/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Itens_do_orcamento]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Itens_do_orcamento"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Itens_do_orcamento"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await Itens_do_orcamentoService.update(
req.body.data,
req.body.id,
req.currentUser,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/itens_do_orcamento/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Itens_do_orcamento]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Itens_do_orcamento"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await Itens_do_orcamentoService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/itens_do_orcamento/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Itens_do_orcamento]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Itens_do_orcamento"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await Itens_do_orcamentoService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/itens_do_orcamento:
* get:
* security:
* - bearerAuth: []
* tags: [Itens_do_orcamento]
* summary: Get all itens_do_orcamento
* description: Get all itens_do_orcamento
* responses:
* 200:
* description: Itens_do_orcamento list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Itens_do_orcamento"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await Itens_do_orcamentoDBApi.findAll(req.query, {
currentUser,
});
if (filetype && filetype === 'csv') {
const fields = ['id', 'quantidade', 'subtotal'];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/itens_do_orcamento/count:
* get:
* security:
* - bearerAuth: []
* tags: [Itens_do_orcamento]
* summary: Count all itens_do_orcamento
* description: Count all itens_do_orcamento
* responses:
* 200:
* description: Itens_do_orcamento count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Itens_do_orcamento"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Itens_do_orcamentoDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/itens_do_orcamento/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Itens_do_orcamento]
* summary: Find all itens_do_orcamento that match search criteria
* description: Find all itens_do_orcamento that match search criteria
* responses:
* 200:
* description: Itens_do_orcamento list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Itens_do_orcamento"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Itens_do_orcamentoDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/itens_do_orcamento/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Itens_do_orcamento]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Itens_do_orcamento"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await Itens_do_orcamentoDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,244 @@
const express = require('express');
const db = require('../db/models');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const sjs = require('sequelize-json-schema');
const { getWidget, askGpt } = require('../services/openai');
const RolesService = require('../services/roles');
const RolesDBApi = require('../db/api/roles');
/**
* @swagger
* /api/roles/roles-info/{infoId}:
* delete:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Remove role information by ID
* description: Remove specific role information by ID
* parameters:
* - in: path
* name: infoId
* description: ID of role information to remove
* required: true
* schema:
* type: string
* - in: query
* name: userId
* description: ID of the user
* required: true
* schema:
* type: string
* - in: query
* name: key
* description: Key of the role information to remove
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Role information successfully removed
* content:
* application/json:
* schema:
* type: object
* properties:
* user:
* type: string
* description: The user information
* 400:
* description: Invalid ID or key supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Role not found
* 500:
* description: Some server error
*/
router.delete(
'/roles-info/:infoId',
wrapAsync(async (req, res) => {
const role = await RolesService.removeRoleInfoById(
req.query.infoId,
req.query.roleId,
req.query.key,
req.currentUser,
);
res.status(200).send(role);
}),
);
/**
* @swagger
* /api/roles/role-info/{roleId}:
* get:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Get role information by key
* description: Get specific role information by key
* parameters:
* - in: path
* name: roleId
* description: ID of role to get information for
* required: true
* schema:
* type: string
* - in: query
* name: key
* description: Key of the role information to retrieve
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Role information successfully received
* content:
* application/json:
* schema:
* type: object
* properties:
* info:
* type: string
* description: The role information
* 400:
* description: Invalid ID or key supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Role not found
* 500:
* description: Some server error
*/
router.get(
'/info-by-key',
wrapAsync(async (req, res) => {
const roleId = req.query.roleId;
const key = req.query.key;
const currentUser = req.currentUser;
let info = await RolesService.getRoleInfoByKey(key, roleId, currentUser);
const role = await RolesDBApi.findBy({ id: roleId });
if (!role?.role_customization) {
await Promise.all(
['pie', 'bar'].map(async (e) => {
const schema = await sjs.getSequelizeSchema(db.sequelize, {});
const payload = {
description: `Create some cool ${e} chart`,
modelDefinition: schema.definitions,
};
const widgetId = await getWidget(payload, currentUser?.id, roleId);
if (widgetId) {
await RolesService.addRoleInfo(
roleId,
currentUser?.id,
'widgets',
widgetId,
req.currentUser,
);
}
}),
);
info = await RolesService.getRoleInfoByKey(key, roleId, currentUser);
}
res.status(200).send(info);
}),
);
router.post(
'/create_widget',
wrapAsync(async (req, res) => {
const { description, userId, roleId } = req.body;
const currentUser = req.currentUser;
const schema = await sjs.getSequelizeSchema(db.sequelize, {});
const payload = {
description,
modelDefinition: schema.definitions,
};
const widgetId = await getWidget(payload, userId, roleId);
if (widgetId) {
await RolesService.addRoleInfo(
roleId,
userId,
'widgets',
widgetId,
currentUser,
);
return res.status(200).send(widgetId);
} else {
return res.status(400).send(widgetId);
}
}),
);
/**
* @swagger
* /api/openai/ask:
* post:
* security:
* - bearerAuth: []
* tags: [OpenAI]
* summary: Ask a question to ChatGPT
* description: Send a question to OpenAI's ChatGPT and get a response
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* question:
* type: string
* description: The question to ask ChatGPT
* apiKey:
* type: string
* description: OpenAI API key
* responses:
* 200:
* description: Question successfully answered
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* description: Whether the request was successful
* data:
* type: string
* description: The answer from ChatGPT
* 400:
* description: Invalid request
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 500:
* description: Some server error
*/
router.post(
'/ask-gpt',
wrapAsync(async (req, res) => {
const { prompt } = req.body;
if (!prompt) {
return res.status(400).send({
success: false,
error: 'Question and API key are required',
});
}
const response = await askGpt(prompt);
if (response.success) {
return res.status(200).send(response);
} else {
return res.status(500).send(response);
}
}),
);
module.exports = router;

View File

@ -0,0 +1,470 @@
const express = require('express');
const OrcamentosService = require('../services/orcamentos');
const OrcamentosDBApi = require('../db/api/orcamentos');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('orcamentos'));
/**
* @swagger
* components:
* schemas:
* Orcamentos:
* type: object
* properties:
* id_orcamento:
* type: string
* default: id_orcamento
* local_do_evento:
* type: string
* default: local_do_evento
* forma_de_pagamento:
* type: string
* default: forma_de_pagamento
* quantidade_parcelas:
* type: integer
* format: int64
* valor_desconto:
* type: integer
* format: int64
* valor_entrada:
* type: integer
* format: int64
* valor_total:
* type: integer
* format: int64
*
*
*/
/**
* @swagger
* tags:
* name: Orcamentos
* description: The Orcamentos managing API
*/
/**
* @swagger
* /api/orcamentos:
* post:
* security:
* - bearerAuth: []
* tags: [Orcamentos]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Orcamentos"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Orcamentos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await OrcamentosService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Orcamentos]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Orcamentos"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Orcamentos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await OrcamentosService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/orcamentos/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Orcamentos]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Orcamentos"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Orcamentos"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await OrcamentosService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/orcamentos/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Orcamentos]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Orcamentos"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await OrcamentosService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/orcamentos/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Orcamentos]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Orcamentos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await OrcamentosService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/orcamentos:
* get:
* security:
* - bearerAuth: []
* tags: [Orcamentos]
* summary: Get all orcamentos
* description: Get all orcamentos
* responses:
* 200:
* description: Orcamentos list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Orcamentos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await OrcamentosDBApi.findAll(req.query, { currentUser });
if (filetype && filetype === 'csv') {
const fields = [
'id',
'id_orcamento',
'local_do_evento',
'forma_de_pagamento',
'quantidade_parcelas',
'valor_desconto',
'valor_entrada',
'valor_total',
'data_do_evento',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/orcamentos/count:
* get:
* security:
* - bearerAuth: []
* tags: [Orcamentos]
* summary: Count all orcamentos
* description: Count all orcamentos
* responses:
* 200:
* description: Orcamentos count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Orcamentos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await OrcamentosDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/orcamentos/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Orcamentos]
* summary: Find all orcamentos that match search criteria
* description: Find all orcamentos that match search criteria
* responses:
* 200:
* description: Orcamentos list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Orcamentos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await OrcamentosDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/orcamentos/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Orcamentos]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Orcamentos"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await OrcamentosDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

View File

@ -0,0 +1,442 @@
const express = require('express');
const PermissionsService = require('../services/permissions');
const PermissionsDBApi = require('../db/api/permissions');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('permissions'));
/**
* @swagger
* components:
* schemas:
* Permissions:
* type: object
* properties:
* name:
* type: string
* default: name
*/
/**
* @swagger
* tags:
* name: Permissions
* description: The Permissions managing API
*/
/**
* @swagger
* /api/permissions:
* post:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Permissions"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await PermissionsService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Permissions"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await PermissionsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/permissions/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Permissions"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Permissions"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await PermissionsService.update(
req.body.data,
req.body.id,
req.currentUser,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/permissions/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Permissions"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await PermissionsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/permissions/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await PermissionsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/permissions:
* get:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Get all permissions
* description: Get all permissions
* responses:
* 200:
* description: Permissions list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await PermissionsDBApi.findAll(req.query, { currentUser });
if (filetype && filetype === 'csv') {
const fields = ['id', 'name'];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/permissions/count:
* get:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Count all permissions
* description: Count all permissions
* responses:
* 200:
* description: Permissions count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await PermissionsDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/permissions/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Find all permissions that match search criteria
* description: Find all permissions that match search criteria
* responses:
* 200:
* description: Permissions list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await PermissionsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/permissions/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Permissions"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await PermissionsDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,106 @@
const express = require('express');
const router = express.Router();
const { pexelsKey, pexelsQuery } = require('../config');
const fetch = require('node-fetch');
const KEY = pexelsKey;
router.get('/image', async (req, res) => {
const headers = {
Authorization: `${KEY}`,
};
const query = pexelsQuery || 'nature';
const orientation = 'portrait';
const perPage = 1;
const url = `https://api.pexels.com/v1/search?query=${query}&orientation=${orientation}&per_page=${perPage}&page=1`;
try {
const response = await fetch(url, { headers });
const data = await response.json();
res.status(200).json(data.photos[0]);
} catch (error) {
res.status(200).json({ error: 'Failed to fetch image' });
}
});
router.get('/video', async (req, res) => {
const headers = {
Authorization: `${KEY}`,
};
const query = pexelsQuery || 'nature';
const orientation = 'portrait';
const perPage = 1;
const url = `https://api.pexels.com/videos/search?query=${query}&orientation=${orientation}&per_page=${perPage}&page=1`;
try {
const response = await fetch(url, { headers });
const data = await response.json();
res.status(200).json(data.videos[0]);
} catch (error) {
res.status(200).json({ error: 'Failed to fetch video' });
}
});
router.get('/multiple-images', async (req, res) => {
const headers = {
Authorization: `${KEY}`,
};
const queries = req.query.queries
? req.query.queries.split(',')
: ['home', 'apple', 'pizza', 'mountains', 'cat'];
const orientation = 'square';
const perPage = 1;
const fallbackImage = {
src: 'https://images.pexels.com/photos/8199252/pexels-photo-8199252.jpeg',
photographer: 'Yan Krukau',
photographer_url: 'https://www.pexels.com/@yankrukov',
};
const fetchFallbackImage = async () => {
try {
const response = await fetch('https://picsum.photos/600');
return {
src: response.url,
photographer: 'Random Picsum',
photographer_url: 'https://picsum.photos/',
};
} catch (error) {
return fallbackImage;
}
};
const fetchImage = async (query) => {
const url = `https://api.pexels.com/v1/search?query=${query}&orientation=${orientation}&per_page=${perPage}&page=1`;
const response = await fetch(url, { headers });
const data = await response.json();
return data.photos[0] || null;
};
const imagePromises = queries.map((query) => fetchImage(query));
const imagesResults = await Promise.allSettled(imagePromises);
const formattedImages = await Promise.all(
imagesResults.map(async (result) => {
if (result.status === 'fulfilled' && result.value) {
const image = result.value;
return {
src: image.src?.original || fallbackImage.src,
photographer: image.photographer || fallbackImage.photographer,
photographer_url:
image.photographer_url || fallbackImage.photographer_url,
};
} else {
const fallback = await fetchFallbackImage();
return {
src: fallback.src || '',
photographer: fallback.photographer || 'Unknown',
photographer_url: fallback.photographer_url || '',
};
}
}),
);
res.json(formattedImages);
});
module.exports = router;

433
backend/src/routes/roles.js Normal file
View File

@ -0,0 +1,433 @@
const express = require('express');
const RolesService = require('../services/roles');
const RolesDBApi = require('../db/api/roles');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('roles'));
/**
* @swagger
* components:
* schemas:
* Roles:
* type: object
* properties:
* name:
* type: string
* default: name
*/
/**
* @swagger
* tags:
* name: Roles
* description: The Roles managing API
*/
/**
* @swagger
* /api/roles:
* post:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Roles"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await RolesService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Roles"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await RolesService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/roles/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Roles"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await RolesService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/roles/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await RolesService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/roles/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await RolesService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/roles:
* get:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Get all roles
* description: Get all roles
* responses:
* 200:
* description: Roles list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await RolesDBApi.findAll(req.query, { currentUser });
if (filetype && filetype === 'csv') {
const fields = ['id', 'name'];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/roles/count:
* get:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Count all roles
* description: Count all roles
* responses:
* 200:
* description: Roles count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await RolesDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/roles/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Find all roles that match search criteria
* description: Find all roles that match search criteria
* responses:
* 200:
* description: Roles list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await RolesDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/roles/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await RolesDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,54 @@
const express = require('express');
const SearchService = require('../services/search');
const router = express.Router();
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('search'));
/**
* @swagger
* path:
* /api/search:
* post:
* summary: Search
* description: Search results across multiple tables
* requestBody:
* content:
* application/json:
* schema:
* type: object
* properties:
* searchQuery:
* type: string
* required:
* - searchQuery
* responses:
* 200:
* description: Successful request
* 400:
* description: Invalid request
* 500:
* description: Internal server error
*/
router.post('/', async (req, res) => {
const { searchQuery } = req.body;
if (!searchQuery) {
return res.status(400).json({ error: 'Please enter a search query' });
}
try {
const foundMatches = await SearchService.search(
searchQuery,
req.currentUser,
);
res.json(foundMatches);
} catch (error) {
console.error('Internal Server Error', error);
res.status(500).json({ error: 'Internal Server Error' });
}
});
module.exports = router;

View File

@ -0,0 +1,462 @@
const express = require('express');
const Servicos_produtosService = require('../services/servicos_produtos');
const Servicos_produtosDBApi = require('../db/api/servicos_produtos');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('servicos_produtos'));
/**
* @swagger
* components:
* schemas:
* Servicos_produtos:
* type: object
* properties:
* nome_do_item:
* type: string
* default: nome_do_item
* descricao:
* type: string
* default: descricao
* unidade:
* type: string
* default: unidade
* preco_unitario:
* type: integer
* format: int64
*
*/
/**
* @swagger
* tags:
* name: Servicos_produtos
* description: The Servicos_produtos managing API
*/
/**
* @swagger
* /api/servicos_produtos:
* post:
* security:
* - bearerAuth: []
* tags: [Servicos_produtos]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Servicos_produtos"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Servicos_produtos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Servicos_produtosService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Servicos_produtos]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Servicos_produtos"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Servicos_produtos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Servicos_produtosService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/servicos_produtos/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Servicos_produtos]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Servicos_produtos"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Servicos_produtos"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await Servicos_produtosService.update(
req.body.data,
req.body.id,
req.currentUser,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/servicos_produtos/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Servicos_produtos]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Servicos_produtos"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await Servicos_produtosService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/servicos_produtos/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Servicos_produtos]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Servicos_produtos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await Servicos_produtosService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/servicos_produtos:
* get:
* security:
* - bearerAuth: []
* tags: [Servicos_produtos]
* summary: Get all servicos_produtos
* description: Get all servicos_produtos
* responses:
* 200:
* description: Servicos_produtos list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Servicos_produtos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await Servicos_produtosDBApi.findAll(req.query, {
currentUser,
});
if (filetype && filetype === 'csv') {
const fields = [
'id',
'nome_do_item',
'descricao',
'unidade',
'preco_unitario',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/servicos_produtos/count:
* get:
* security:
* - bearerAuth: []
* tags: [Servicos_produtos]
* summary: Count all servicos_produtos
* description: Count all servicos_produtos
* responses:
* 200:
* description: Servicos_produtos count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Servicos_produtos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Servicos_produtosDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/servicos_produtos/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Servicos_produtos]
* summary: Find all servicos_produtos that match search criteria
* description: Find all servicos_produtos that match search criteria
* responses:
* 200:
* description: Servicos_produtos list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Servicos_produtos"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Servicos_produtosDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/servicos_produtos/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Servicos_produtos]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Servicos_produtos"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await Servicos_produtosDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

444
backend/src/routes/users.js Normal file
View File

@ -0,0 +1,444 @@
const express = require('express');
const UsersService = require('../services/users');
const UsersDBApi = require('../db/api/users');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('users'));
/**
* @swagger
* components:
* schemas:
* Users:
* type: object
* properties:
* firstName:
* type: string
* default: firstName
* lastName:
* type: string
* default: lastName
* phoneNumber:
* type: string
* default: phoneNumber
* email:
* type: string
* default: email
*/
/**
* @swagger
* tags:
* name: Users
* description: The Users managing API
*/
/**
* @swagger
* /api/users:
* post:
* security:
* - bearerAuth: []
* tags: [Users]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Users"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Users"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await UsersService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Users]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Users"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Users"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await UsersService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/users/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Users]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Users"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Users"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await UsersService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/users/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Users]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Users"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await UsersService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/users/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Users]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Users"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await UsersService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/users:
* get:
* security:
* - bearerAuth: []
* tags: [Users]
* summary: Get all users
* description: Get all users
* responses:
* 200:
* description: Users list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Users"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await UsersDBApi.findAll(req.query, { currentUser });
if (filetype && filetype === 'csv') {
const fields = ['id', 'firstName', 'lastName', 'phoneNumber', 'email'];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/users/count:
* get:
* security:
* - bearerAuth: []
* tags: [Users]
* summary: Count all users
* description: Count all users
* responses:
* 200:
* description: Users count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Users"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await UsersDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/users/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Users]
* summary: Find all users that match search criteria
* description: Find all users that match search criteria
* responses:
* 200:
* description: Users list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Users"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await UsersDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/users/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Users]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Users"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await UsersDBApi.findBy({ id: req.params.id });
delete payload.password;
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,444 @@
const express = require('express');
const UsuariosService = require('../services/usuarios');
const UsuariosDBApi = require('../db/api/usuarios');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('usuarios'));
/**
* @swagger
* components:
* schemas:
* Usuarios:
* type: object
* properties:
* nome:
* type: string
* default: nome
* email:
* type: string
* default: email
* senha:
* type: string
* default: senha
*/
/**
* @swagger
* tags:
* name: Usuarios
* description: The Usuarios managing API
*/
/**
* @swagger
* /api/usuarios:
* post:
* security:
* - bearerAuth: []
* tags: [Usuarios]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Usuarios"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Usuarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post(
'/',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await UsuariosService.create(
req.body.data,
req.currentUser,
true,
link.host,
);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Usuarios]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Usuarios"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Usuarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
const referer =
req.headers.referer ||
`${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await UsuariosService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/usuarios/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Usuarios]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Usuarios"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Usuarios"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put(
'/:id',
wrapAsync(async (req, res) => {
await UsuariosService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/usuarios/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Usuarios]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Usuarios"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await UsuariosService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/usuarios/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Usuarios]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Usuarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await UsuariosService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/usuarios:
* get:
* security:
* - bearerAuth: []
* tags: [Usuarios]
* summary: Get all usuarios
* description: Get all usuarios
* responses:
* 200:
* description: Usuarios list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Usuarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const payload = await UsuariosDBApi.findAll(req.query, { currentUser });
if (filetype && filetype === 'csv') {
const fields = ['id', 'nome', 'email', 'senha'];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}),
);
/**
* @swagger
* /api/usuarios/count:
* get:
* security:
* - bearerAuth: []
* tags: [Usuarios]
* summary: Count all usuarios
* description: Count all usuarios
* responses:
* 200:
* description: Usuarios count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Usuarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get(
'/count',
wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await UsuariosDBApi.findAll(req.query, null, {
countOnly: true,
currentUser,
});
res.status(200).send(payload);
}),
);
/**
* @swagger
* /api/usuarios/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Usuarios]
* summary: Find all usuarios that match search criteria
* description: Find all usuarios that match search criteria
* responses:
* 200:
* description: Usuarios list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Usuarios"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await UsuariosDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/usuarios/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Usuarios]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Usuarios"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await UsuariosDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -0,0 +1,226 @@
const UsersDBApi = require('../db/api/users');
const ValidationError = require('./notifications/errors/validation');
const ForbiddenError = require('./notifications/errors/forbidden');
const bcrypt = require('bcrypt');
const EmailAddressVerificationEmail = require('./email/list/addressVerification');
const InvitationEmail = require('./email/list/invitation');
const PasswordResetEmail = require('./email/list/passwordReset');
const EmailSender = require('./email');
const config = require('../config');
const helpers = require('../helpers');
class Auth {
static async signup(email, password, options = {}, host) {
const user = await UsersDBApi.findBy({ email });
const hashedPassword = await bcrypt.hash(
password,
config.bcrypt.saltRounds,
);
if (user) {
if (user.authenticationUid) {
throw new ValidationError('auth.emailAlreadyInUse');
}
if (user.disabled) {
throw new ValidationError('auth.userDisabled');
}
await UsersDBApi.updatePassword(user.id, hashedPassword, options);
if (EmailSender.isConfigured) {
await this.sendEmailAddressVerificationEmail(user.email, host);
}
const data = {
user: {
id: user.id,
email: user.email,
},
};
return helpers.jwtSign(data);
}
const newUser = await UsersDBApi.createFromAuth(
{
firstName: email.split('@')[0],
password: hashedPassword,
email: email,
},
options,
);
if (EmailSender.isConfigured) {
await this.sendEmailAddressVerificationEmail(newUser.email, host);
}
const data = {
user: {
id: newUser.id,
email: newUser.email,
},
};
return helpers.jwtSign(data);
}
static async signin(email, password, options = {}) {
const user = await UsersDBApi.findBy({ email });
if (!user) {
throw new ValidationError('auth.userNotFound');
}
if (user.disabled) {
throw new ValidationError('auth.userDisabled');
}
if (!user.password) {
throw new ValidationError('auth.wrongPassword');
}
if (!EmailSender.isConfigured) {
user.emailVerified = true;
}
if (!user.emailVerified) {
throw new ValidationError('auth.userNotVerified');
}
const passwordsMatch = await bcrypt.compare(password, user.password);
if (!passwordsMatch) {
throw new ValidationError('auth.wrongPassword');
}
const data = {
user: {
id: user.id,
email: user.email,
},
};
return helpers.jwtSign(data);
}
static async sendEmailAddressVerificationEmail(email, host) {
let link;
try {
const token = await UsersDBApi.generateEmailVerificationToken(email);
link = `${host}/verify-email?token=${token}`;
} catch (error) {
console.error(error);
throw new ValidationError('auth.emailAddressVerificationEmail.error');
}
const emailAddressVerificationEmail = new EmailAddressVerificationEmail(
email,
link,
);
return new EmailSender(emailAddressVerificationEmail).send();
}
static async sendPasswordResetEmail(email, type = 'register', host) {
let link;
try {
const token = await UsersDBApi.generatePasswordResetToken(email);
link = `${host}/password-reset?token=${token}`;
} catch (error) {
console.error(error);
throw new ValidationError('auth.passwordReset.error');
}
let passwordResetEmail;
if (type === 'register') {
passwordResetEmail = new PasswordResetEmail(email, link);
}
if (type === 'invitation') {
passwordResetEmail = new InvitationEmail(email, link);
}
return new EmailSender(passwordResetEmail).send();
}
static async verifyEmail(token, options = {}) {
const user = await UsersDBApi.findByEmailVerificationToken(token, options);
if (!user) {
throw new ValidationError(
'auth.emailAddressVerificationEmail.invalidToken',
);
}
return UsersDBApi.markEmailVerified(user.id, options);
}
static async passwordUpdate(currentPassword, newPassword, options) {
const currentUser = options.currentUser || null;
if (!currentUser) {
throw new ForbiddenError();
}
const currentPasswordMatch = await bcrypt.compare(
currentPassword,
currentUser.password,
);
if (!currentPasswordMatch) {
throw new ValidationError('auth.wrongPassword');
}
const newPasswordMatch = await bcrypt.compare(
newPassword,
currentUser.password,
);
if (newPasswordMatch) {
throw new ValidationError('auth.passwordUpdate.samePassword');
}
const hashedPassword = await bcrypt.hash(
newPassword,
config.bcrypt.saltRounds,
);
return UsersDBApi.updatePassword(currentUser.id, hashedPassword, options);
}
static async passwordReset(token, password, options = {}) {
const user = await UsersDBApi.findByPasswordResetToken(token, options);
if (!user) {
throw new ValidationError('auth.passwordReset.invalidToken');
}
const hashedPassword = await bcrypt.hash(
password,
config.bcrypt.saltRounds,
);
return UsersDBApi.updatePassword(user.id, hashedPassword, options);
}
static async updateProfile(data, currentUser) {
let transaction = await db.sequelize.transaction();
try {
await UsersDBApi.findBy({ id: currentUser.id }, { transaction });
await UsersDBApi.update(currentUser.id, data, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
}
module.exports = Auth;

View File

@ -0,0 +1,114 @@
const db = require('../db/models');
const ClientesDBApi = require('../db/api/clientes');
const processFile = require('../middlewares/upload');
const ValidationError = require('./notifications/errors/validation');
const csv = require('csv-parser');
const axios = require('axios');
const config = require('../config');
const stream = require('stream');
module.exports = class ClientesService {
static async create(data, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await ClientesDBApi.create(data, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async bulkImport(req, res, sendInvitationEmails = true, host) {
const transaction = await db.sequelize.transaction();
try {
await processFile(req, res);
const bufferStream = new stream.PassThrough();
const results = [];
await bufferStream.end(Buffer.from(req.file.buffer, 'utf-8')); // convert Buffer to Stream
await new Promise((resolve, reject) => {
bufferStream
.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', async () => {
console.log('CSV results', results);
resolve();
})
.on('error', (error) => reject(error));
});
await ClientesDBApi.bulkImport(results, {
transaction,
ignoreDuplicates: true,
validate: true,
currentUser: req.currentUser,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async update(data, id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
let clientes = await ClientesDBApi.findBy({ id }, { transaction });
if (!clientes) {
throw new ValidationError('clientesNotFound');
}
const updatedClientes = await ClientesDBApi.update(id, data, {
currentUser,
transaction,
});
await transaction.commit();
return updatedClientes;
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async deleteByIds(ids, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await ClientesDBApi.deleteByIds(ids, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async remove(id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await ClientesDBApi.remove(id, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
};

View File

@ -0,0 +1,117 @@
const db = require('../db/models');
const Contas_a_pagarDBApi = require('../db/api/contas_a_pagar');
const processFile = require('../middlewares/upload');
const ValidationError = require('./notifications/errors/validation');
const csv = require('csv-parser');
const axios = require('axios');
const config = require('../config');
const stream = require('stream');
module.exports = class Contas_a_pagarService {
static async create(data, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await Contas_a_pagarDBApi.create(data, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async bulkImport(req, res, sendInvitationEmails = true, host) {
const transaction = await db.sequelize.transaction();
try {
await processFile(req, res);
const bufferStream = new stream.PassThrough();
const results = [];
await bufferStream.end(Buffer.from(req.file.buffer, 'utf-8')); // convert Buffer to Stream
await new Promise((resolve, reject) => {
bufferStream
.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', async () => {
console.log('CSV results', results);
resolve();
})
.on('error', (error) => reject(error));
});
await Contas_a_pagarDBApi.bulkImport(results, {
transaction,
ignoreDuplicates: true,
validate: true,
currentUser: req.currentUser,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async update(data, id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
let contas_a_pagar = await Contas_a_pagarDBApi.findBy(
{ id },
{ transaction },
);
if (!contas_a_pagar) {
throw new ValidationError('contas_a_pagarNotFound');
}
const updatedContas_a_pagar = await Contas_a_pagarDBApi.update(id, data, {
currentUser,
transaction,
});
await transaction.commit();
return updatedContas_a_pagar;
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async deleteByIds(ids, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await Contas_a_pagarDBApi.deleteByIds(ids, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async remove(id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await Contas_a_pagarDBApi.remove(id, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
};

View File

@ -0,0 +1,121 @@
const db = require('../db/models');
const Contas_a_receberDBApi = require('../db/api/contas_a_receber');
const processFile = require('../middlewares/upload');
const ValidationError = require('./notifications/errors/validation');
const csv = require('csv-parser');
const axios = require('axios');
const config = require('../config');
const stream = require('stream');
module.exports = class Contas_a_receberService {
static async create(data, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await Contas_a_receberDBApi.create(data, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async bulkImport(req, res, sendInvitationEmails = true, host) {
const transaction = await db.sequelize.transaction();
try {
await processFile(req, res);
const bufferStream = new stream.PassThrough();
const results = [];
await bufferStream.end(Buffer.from(req.file.buffer, 'utf-8')); // convert Buffer to Stream
await new Promise((resolve, reject) => {
bufferStream
.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', async () => {
console.log('CSV results', results);
resolve();
})
.on('error', (error) => reject(error));
});
await Contas_a_receberDBApi.bulkImport(results, {
transaction,
ignoreDuplicates: true,
validate: true,
currentUser: req.currentUser,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async update(data, id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
let contas_a_receber = await Contas_a_receberDBApi.findBy(
{ id },
{ transaction },
);
if (!contas_a_receber) {
throw new ValidationError('contas_a_receberNotFound');
}
const updatedContas_a_receber = await Contas_a_receberDBApi.update(
id,
data,
{
currentUser,
transaction,
},
);
await transaction.commit();
return updatedContas_a_receber;
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async deleteByIds(ids, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await Contas_a_receberDBApi.deleteByIds(ids, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async remove(id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await Contas_a_receberDBApi.remove(id, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
};

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<style>
.email-container {
max-width: 600px;
margin: auto;
background-color: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 4px;
overflow: hidden;
}
.email-header {
background-color: #3498db;
color: #fff;
padding: 16px;
text-align: center;
}
.email-body {
padding: 16px;
}
.email-footer {
padding: 16px;
background-color: #f7fafc;
text-align: center;
color: #4a5568;
font-size: 14px;
}
.link-primary {
color: #3498db;
text-decoration: none;
}
</style>
</head>
<body>
<div class="email-container">
<div class="email-header">Verify your email for {appTitle}!</div>
<div class="email-body">
<p>Hello,</p>
<p>Follow this link to verify your email address.</p>
<p>
If you didn't ask to verify this address, you can ignore this email.
</p>
<p><a href="{signupUrl}" class="link-primary">{signupUrl}</a></p>
</div>
<div class="email-footer">
Thanks,<br />
The {appTitle} Team
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<style>
.email-container {
max-width: 600px;
margin: auto;
background-color: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 4px;
overflow: hidden;
}
.email-header {
background-color: #3498db;
color: #fff;
padding: 16px;
text-align: center;
}
.email-body {
padding: 16px;
}
.email-footer {
padding: 16px;
background-color: #f7fafc;
text-align: center;
color: #4a5568;
font-size: 14px;
}
.btn-primary {
background-color: #3498db;
color: #fff !important;
padding: 8px 16px;
border-radius: 4px;
text-decoration: none;
display: inline-block;
}
</style>
</head>
<body>
<div class="email-container">
<div class="email-header">Welcome to {appTitle}!</div>
<div class="email-body">
<p>Hello,</p>
<p>
You've been invited to join {appTitle}. Please click the button below
to set up your account.
</p>
<a href="{signupUrl}" class="btn-primary">Set up account</a>
</div>
<div class="email-footer">
Thanks,<br />
The {appTitle} Team
</div>
</div>
</body>
</html>

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