Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions modulo5/dtos/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.env
.DS_STORE
node_modules
build
3,114 changes: 3,114 additions & 0 deletions modulo5/dtos/package-lock.json

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions modulo5/dtos/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "projeto-cookenu-backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node ./build/index.js",
"build": "tsc",
"dev": "ts-node-dev ./src/index.ts",
"migrations": "tsc && node ./build/database/migrations/Migrations.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/cors": "^2.8.12",
"@types/express": "^4.17.13",
"@types/jsonwebtoken": "^8.5.8",
"@types/knex": "^0.16.1",
"@types/node": "^18.0.6",
"@types/uuid": "^8.3.4",
"@types/bcryptjs": "^2.4.2",
"ts-node-dev": "^2.0.0",
"typescript": "^4.7.4"
},
"dependencies": {
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.0.1",
"express": "^4.18.1",
"jsonwebtoken": "^8.5.1",
"knex": "^2.2.0",
"mysql": "^2.18.1",
"uuid": "^8.3.2"
}
}
35 changes: 35 additions & 0 deletions modulo5/dtos/requests.rest
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
### 1) Signup
POST http://localhost:3003/users/signup
Content-Type: application/json

{
"name": "Beltrano",
"email": "beltrano@gmail.com",
"password": "abc123"
}

### 2) Login
POST http://localhost:3003/users/login
Content-Type: application/json

{
"email": "astrodev@gmail.com",
"password": "bananinha"
}

### 3) Get users
GET http://localhost:3003/users
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImJkOTVjOTM3LTM0MDYtNDI0OC05ZTBmLWQ0ZGQyZGJjYjE2NSIsInJvbGUiOiJOT1JNQUwiLCJpYXQiOjE2NjM2NzY3ODIsImV4cCI6MTY2Mzc2MzE4Mn0.lRWQmLiwk8SEdMWLFUNub3DeTsUF2NKmuFQTB29vKMQ

### 4) Delete user
DELETE http://localhost:3003/users/b67c6ee5-c06b-470f-8470-71803e17e509
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImJiOWI3ZWU4LWFlNGItNGJkMS05YmQ2LWU3ZTIxNTk0Mzk5YiIsInJvbGUiOiJBRE1JTiIsImlhdCI6MTY2MDA1MDUyMCwiZXhwIjoxNjYwMTM2OTIwfQ.aLmP8EirhZQ1nPweO2dwNd43uQLIzSbctXklgL04TOk

### EXTRA) Edit user
PUT http://localhost:3003/users/bb9b7ee8-ae4b-4bd1-9bd6-e7e21594399b
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjIwMzM3NWRkLThiMzItNGU1My04NWViLWViYTkxNDQzZmIzZSIsInJvbGUiOiJOT1JNQUwiLCJpYXQiOjE2NjAwNTI2NDEsImV4cCI6MTY2MDEzOTA0MX0.jOF6vSbGc8AuQAf82UJ1bKC_Xle9YNuKYl3SRFh2Ex0
Content-Type: application/json

{
"name": "Astrodev3"
}
299 changes: 299 additions & 0 deletions modulo5/dtos/src/business/UserBusiness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
import { UserDatabase } from "../database/UserDatabase"
import { IGetUsersInputDBDTO, IGetUsersInputDTO, ISignupInputDTO, ISignupOutputDTO, User, USER_ROLES } from "../models/User"
import { Authenticator, ITokenPayload } from "../services/Authenticator"
import { HashManager } from "../services/HashManager"
import { IdGenerator } from "../services/IdGenerator"

export class UserBusiness {
public signup = async (input: ISignupInputDTO) => {
const name = input.name
const email = input.email
const password = input.password

if (!name || !email || !password) {
throw new Error("Um ou mais parâmetros faltando")
}

if (typeof name !== "string" || name.length < 3) {
throw new Error("Parâmetro 'name' inválido")
}

if (typeof email !== "string" || email.length < 3) {
throw new Error("Parâmetro 'email' inválido")
}

if (!email.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)) {
throw new Error("Parâmetro 'email' inválido")
}

if (typeof password !== "string" || password.length < 3) {
throw new Error("Parâmetro 'password' inválido")
}

const userDatabase = new UserDatabase()
const userDB = await userDatabase.findByEmail(email)

if (userDB) {
throw new Error("E-mail já cadastrado")
}

const idGenerator = new IdGenerator()
const hashManager = new HashManager()

const id = idGenerator.generate()
const hashedPassword = await hashManager.hash(password)

const user = new User(
id,
name,
email,
hashedPassword,
USER_ROLES.NORMAL
)

await userDatabase.createUser(user)

const payload: ITokenPayload = {
id: user.getId(),
role: user.getRole()
}

const authenticator = new Authenticator()
const token = authenticator.generateToken(payload)

const response: ISignupOutputDTO = {
message: "Cadastro realizado com sucesso",
token
}

return response
}

public login = async (input: any) => {
const email = input.email
const password = input.password

if (!email || !password) {
throw new Error("Um ou mais parâmetros faltando")
}

if (typeof email !== "string" || email.length < 3) {
throw new Error("Parâmetro 'email' inválido")
}

if (!email.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)) {
throw new Error("Parâmetro 'email' inválido")
}

if (typeof password !== "string" || password.length < 3) {
throw new Error("Parâmetro 'password' inválido")
}

const userDatabase = new UserDatabase()
const userDB = await userDatabase.findByEmail(email)

if (!userDB) {
throw new Error("E-mail não cadastrado")
}

const user = new User(
userDB.id,
userDB.name,
userDB.email,
userDB.password,
userDB.role
)

const hashManager = new HashManager()
const isPasswordCorrect = await hashManager.compare(password, user.getPassword())

if (!isPasswordCorrect) {
throw new Error("Senha incorreta")
}

const payload: ITokenPayload = {
id: user.getId(),
role: user.getRole()
}

const authenticator = new Authenticator()
const token = authenticator.generateToken(payload)

const response = {
message: "Login realizado com sucesso",
token
}

return response
}

public getUsers = async (input: IGetUsersInputDTO) => {
const token = input.token
const search = input.search || ""
const order = input.order || "name"
const sort = input.sort || "ASC"
const limit = Number(input.limit) || 10
const page = Number(input.page) || 1

const offset = limit * (page - 1)

const authenticator = new Authenticator()
const payload = authenticator.getTokenPayload(token)

if (!payload) {
throw new Error("Token inválido ou faltando")
}

const getUsersInputDB: IGetUsersInputDBDTO = {
search,
order,
sort,
limit,
offset
}

const userDatabase = new UserDatabase()
const usersDB = await userDatabase.getUsers(getUsersInputDB)

const users = usersDB.map(userDB => {
const user = new User(
userDB.id,
userDB.name,
userDB.email,
userDB.password,
userDB.role
)

const userResponse: any = {
id: user.getId(),
name: user.getName(),
email: user.getEmail()
}

return userResponse
})

const response: any = {
users
}

return response
}

public deleteUser = async (input: any) => {
const token = input.token
const idToDelete = input.idToDelete

const authenticator = new Authenticator()
const payload = authenticator.getTokenPayload(token)

if (!payload) {
throw new Error("Token inválido ou faltando")
}

if (payload.role !== USER_ROLES.ADMIN) {
throw new Error("Apenas admins podem deletar usuários")
}

if (payload.id === idToDelete) {
throw new Error("Não é possível deletar a própria conta")
}

const userDatabase = new UserDatabase()
const userDB = await userDatabase.findById(idToDelete)

if (!userDB) {
throw new Error("Usuário a ser deletado não encontrado")
}

await userDatabase.deleteUser(idToDelete)

const response = {
message: "Usuário deletado com sucesso"
}

return response
}

public editUser = async (input: any) => {
const {
token,
idToEdit,
email,
name,
password
} = input

if (!token) {
throw new Error("Token faltando")
}

if (!email && !name && !password) {
throw new Error("Parâmetros faltando")
}

const authenticator = new Authenticator()
const payload = authenticator.getTokenPayload(token)

if (!payload) {
throw new Error("Token inválido")
}

if (email && typeof email !== "string") {
throw new Error("Parâmetro 'email' inválido")
}

if (email && !email.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)) {
throw new Error("Parâmetro 'email' inválido")
}

if (name && typeof name !== "string") {
throw new Error("Parâmetro 'name' inválido")
}

if (name && name.length < 3) {
throw new Error("Parâmetro 'name' inválido")
}

if (password && typeof password !== "string") {
throw new Error("Parâmetro 'password' inválido")
}

if (password && password.length < 6) {
throw new Error("Parâmetro 'password' inválido")
}

if (payload.role === USER_ROLES.NORMAL) {
if (payload.id !== idToEdit) {
throw new Error("Usuários normais só podem editar a própria conta")
}
}

const userDatabase = new UserDatabase()
const userDB = await userDatabase.findById(idToEdit)

if (!userDB) {
throw new Error("Conta a ser editada não existe")
}

const user = new User(
userDB.id,
userDB.name,
userDB.email,
userDB.password,
userDB.role
)

name && user.setName(name)
email && user.setEmail(email)
password && user.setPassword(password)

await userDatabase.editUser(user)

const response = {
message: "Edição realizada com sucesso"
}

return response
}
}
Loading