Skip to content

Commit

Permalink
feat(createUnitInCompany/createUser): add new authController and create
Browse files Browse the repository at this point in the history
Controller
  • Loading branch information
Fabio Brasileiro authored and Fabio Brasileiro committed Sep 24, 2024
1 parent 14a409c commit 6c5bc56
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 24 deletions.
23 changes: 23 additions & 0 deletions prisma/migrations/20240924005213_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Warnings:
- A unique constraint covering the columns `[name]` on the table `Company` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[document]` on the table `Company` will be added. If there are existing duplicate values, this will fail.
- Added the required column `document` to the `Company` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "Company" ADD COLUMN "document" TEXT NOT NULL;

-- AlterTable
ALTER TABLE "User" ADD COLUMN "companyId" INTEGER;

-- CreateIndex
CREATE UNIQUE INDEX "Company_name_key" ON "Company"("name");

-- CreateIndex
CREATE UNIQUE INDEX "Company_document_key" ON "Company"("document");

-- AddForeignKey
ALTER TABLE "User" ADD CONSTRAINT "User_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;

21 changes: 13 additions & 8 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,30 @@ model Product {
}

model Company {
id Int @id @default(autoincrement())
name String
id Int @id @default(autoincrement())
name String @unique
document String @unique // Certifique-se de que esta linha existe
users User[] // Relação com os usuários
units Unit[]
products Product[]
}

model Unit {
id Int @id @default(autoincrement())
name String
company Company @relation(fields: [companyId], references: [id])
companyId Int
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String
password String
role UserRole
company Company? @relation(fields: [companyId], references: [id])
companyId Int?
}

model Unit {
id Int @id @default(autoincrement())
name String
company Company @relation(fields: [companyId], references: [id])
companyId Int
}

enum UserRole {
Expand Down
1 change: 1 addition & 0 deletions src/@types/express.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ declare global {
namespace Express {
interface Request {
user?: {
id: any
role: UserRole
// Adicione outras propriedades do usuário, se necessário
}
Expand Down
5 changes: 5 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import express from 'express'
import authRoutes from './routes/authRoutes.js'
import paymentRoutes from './routes/paymentRoutes.js'
import productRoutes from './routes/productRoutes.js'
import createUserRouter from './routes/createUserRoutes.js'
import createUnitRouter from './routes/createUnitRoutes.js'

const app = express()

Expand All @@ -18,5 +20,8 @@ app.get('/', (_req, res) => {
app.use('/api/products', productRoutes)
app.use('/api/payments', paymentRoutes)
app.use('/api', authRoutes) // Adicione '/api' como prefixo para as rotas de autenticação
app.use('/api', createUserRouter) // Adicione '/api' como prefixo para as rotas de autenticação
app.use('/api', createUnitRouter) // Adicione '/api' como prefixo para as rotas de autenticação


export default app
67 changes: 53 additions & 14 deletions src/controllers/authController.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { PrismaClient, User } from '@prisma/client'
import { PrismaClient } from '@prisma/client'
import bcrypt from 'bcrypt'
import type { Request, Response } from 'express'
import jwt from 'jsonwebtoken'
import type { Request, Response } from 'express'
import * as companyService from '../services/companyService'

const prisma = new PrismaClient()
const saltRounds = 10

export const register = async (req: Request, res: Response) => {
const { email, password, name, role } = req.body
const { email, password, name, role, companyName, companyDocument } = req.body

try {
// Verificar se o usuário já existe
Expand All @@ -19,33 +20,63 @@ export const register = async (req: Request, res: Response) => {
return res.status(400).json({ message: 'User already exists' })
}

// Verificar se a empresa já existe
const existingCompany = await prisma.company.findUnique({
where: { name: companyName, document: companyDocument },
})

let companyId: number

if (!existingCompany) {
// Criar a empresa
const newCompany = await companyService.createCompany({
name: companyName,
document: companyDocument, // Documento da empresa (CNPJ ou outro)
})

companyId = newCompany.id
} else {
companyId = existingCompany.id
}

// Criptografar a senha
const hashedPassword = await bcrypt.hash(password, saltRounds)

// Criar um novo usuário
// Criar um novo usuário e associá-lo à empresa
const newUser = await prisma.user.create({
data: {
email,
password: hashedPassword,
name,
role, // Supondo que role é uma propriedade opcional
role: role || 'ADMIN', // O primeiro usuário será ADMIN
company: { connect: { id: companyId } }, // Associa o usuário à empresa
},
})

res
.status(201)
.json({ message: 'User created successfully', user: newUser })
// Gerar token JWT
const token = jwt.sign(
{ id: newUser.id, email: newUser.email, role: newUser.role },
process.env.JWT_SECRET || 'your_jwt_secret',
{ expiresIn: '1d' }
)

res.status(201).json({
message: 'User and company created successfully',
user: newUser,
token,
})
} catch (error) {
console.error(error)
res.status(500).json({ message: 'Server error' })
}
}


export const login = async (req: Request, res: Response) => {
const { email, password } = req.body

try {
// Encontrar o usuário pelo email
// Verificar se o usuário existe
const user = await prisma.user.findUnique({
where: { email },
})
Expand All @@ -54,24 +85,32 @@ export const login = async (req: Request, res: Response) => {
return res.status(401).json({ message: 'Invalid credentials' })
}

// Verificar a senha
// Verificar se a senha está correta
const isPasswordValid = await bcrypt.compare(password, user.password)

if (!isPasswordValid) {
return res.status(401).json({ message: 'Invalid credentials' })
}

const horaParaDias: string = `${24 * 356}h`
// Gerar token JWT
const token = jwt.sign(
{ id: user.id, email: user.email, role: user.role },
process.env.JWT_SECRET || 'your_jwt_secret',
{ expiresIn: horaParaDias } // 8544h == 356 dias
{ expiresIn: '1d' }
)

res.status(200).json({ token })
// Retornar o token e as informações do usuário
res.status(200).json({
message: 'Login successful',
token,
user: {
id: user.id,
email: user.email,
role: user.role,
},
})
} catch (error) {
console.error(error)
res.status(500).json({ message: 'Server error' })
}
}
}
48 changes: 48 additions & 0 deletions src/controllers/createUnitInCompany.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { PrismaClient } from '@prisma/client'
import type { Request, Response } from 'express'

const prisma = new PrismaClient()

export const createUnitInCompany = async (req: Request, res: Response) => {
const { name } = req.body

// Verificar se o usuário está autenticado
if (!req.user || !req.user.id) {
return res.status(401).json({ message: 'User not authenticated' })
}

const adminUserId = req.user.id // Pega o ID do usuário autenticado

try {
// Verificar se o usuário autenticado é realmente um ADMIN
const adminUser = await prisma.user.findUnique({
where: { id: adminUserId },
include: { company: true }, // Incluir a empresa relacionada
})

if (!adminUser || adminUser.role !== 'ADMIN') {
return res.status(403).json({ message: 'Only administrators can create units.' })
}

// Verifica se o adminUser tem uma empresa associada
if (!adminUser.companyId) {
return res.status(400).json({ message: 'Admin user does not have a company associated.' })
}

// Criar a nova unidade e associá-la à empresa do administrador
const newUnit = await prisma.unit.create({
data: {
name,
company: { connect: { id: adminUser.companyId } }, // Associa a unidade à empresa do administrador
},
})

res.status(201).json({
message: 'Unit created successfully',
unit: newUnit,
})
} catch (error) {
console.error(error)
res.status(500).json({ message: 'Server error' })
}
}
65 changes: 65 additions & 0 deletions src/controllers/createUserController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { PrismaClient } from '@prisma/client'
import bcrypt from 'bcrypt'
import type { Request, Response } from 'express'

const prisma = new PrismaClient()
const saltRounds = 10

export const createUserInCompany = async (req: Request, res: Response) => {
const { email, password, name, role } = req.body

// Verifica se req.user existe antes de tentar acessá-lo
if (!req.user || !req.user.id) {
return res.status(401).json({ message: 'User not authenticated' })
}

const adminUserId = req.user.id // Pega o ID do usuário autenticado (administrador)

try {
// Verificar se o usuário autenticado é realmente um ADMIN
const adminUser = await prisma.user.findUnique({
where: { id: adminUserId },
include: { company: true }, // Incluir a empresa relacionada
})

if (!adminUser || adminUser.role !== 'ADMIN') {
return res.status(403).json({ message: 'Only administrators can create users.' })
}

// Verifica se o adminUser tem uma empresa associada
if (!adminUser.companyId) {
return res.status(400).json({ message: 'Admin user does not have a company associated.' })
}

// Verificar se o email já existe
const existingUser = await prisma.user.findUnique({
where: { email },
})

if (existingUser) {
return res.status(400).json({ message: 'User already exists' })
}

// Criptografar a senha
const hashedPassword = await bcrypt.hash(password, saltRounds)

// Criar o novo usuário e associá-lo à mesma empresa do administrador
const newUser = await prisma.user.create({
data: {
email,
password: hashedPassword,
name,
role: role || 'USER', // Por padrão, novos usuários são do tipo 'USER'
company: { connect: { id: adminUser.companyId } }, // Associa o novo usuário à empresa do admin
},
})

res.status(201).json({
message: 'User created successfully',
user: newUser,
})
} catch (error) {
console.error(error)
res.status(500).json({ message: 'Server error' })
}
}
11 changes: 11 additions & 0 deletions src/routes/createUnitRoutes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import express from 'express'
import { createUnitInCompany } from '@/controllers/createUnitInCompany'
import authenticate from '../middleware/authenticate'
import authorize from '../middleware/authorize'

const createUnitRouter = express.Router()

// Rota protegida para criar unidades dentro da empresa do administrador
createUnitRouter.post('/create-unit', authenticate, authorize(['ADMIN']), createUnitInCompany)

export default createUnitRouter
11 changes: 11 additions & 0 deletions src/routes/createUserRoutes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import express from 'express'
import { createUserInCompany } from '@/controllers/createUserController'
import authenticate from '../middleware/authenticate'
import authorize from '../middleware/authorize'

const createUserRouter = express.Router()

// Rota protegida para criar usuários dentro da empresa do administrador
createUserRouter.post('/create-user', authenticate, authorize(['ADMIN']), createUserInCompany)

export default createUserRouter
7 changes: 5 additions & 2 deletions src/services/companyService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ const prisma = new PrismaClient()

export const createCompany = async (companyData: Prisma.CompanyCreateInput) => {
return prisma.company.create({
data: companyData
data: {
name: companyData.name,
document: companyData.document,
}
})
}

Expand All @@ -27,7 +30,7 @@ export const updateCompany = async (
where: { id },
data: companyData,
})
}
}

export const deleteCompany = async (id: number) => {
return prisma.company.delete({
Expand Down
9 changes: 9 additions & 0 deletions src/utils/validators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const validateCNPJ = (cnpj: string) => {
// Adicione aqui a lógica de validação de CNPJ
return true // Retorne true se for válido, false se não for
}

export const validateCPF = (cpf: string) => {
// Adicione aqui a lógica de validação de CPF
return true // Retorne true se for válido, false se não for
}

0 comments on commit 6c5bc56

Please sign in to comment.