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
3,114 changes: 3,114 additions & 0 deletions MODULO 5/Labook/package-lock.json

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions MODULO 5/Labook/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"
}
}
46 changes: 46 additions & 0 deletions MODULO 5/Labook/requests.rest
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
### Endpoint de teste
GET http://localhost:3003/ping

### 1) Signup
POST http://localhost:3003/users/signup
Content-Type: application/json

{
"name": "alice",
"email": "alice@gmail.com",
"password": "alice99"
}

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

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

### 3) Create post
POST http://localhost:3003/posts
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEwMSIsInJvbGUiOiJBRE1JTiIsImlhdCI6MTY2MDM5Mzk2MSwiZXhwIjoxNjYwNDgwMzYxfQ.FwOtXHKx1XXFnMot-CJstZPCzEORAtPrwd3iz8QAg5A
Content-Type: application/json

{
"content": "Hello world!"
}

### 4) Get posts
GET http://localhost:3003/posts
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEwMSIsInJvbGUiOiJBRE1JTiIsImlhdCI6MTY2MDM5Mzk2MSwiZXhwIjoxNjYwNDgwMzYxfQ.FwOtXHKx1XXFnMot-CJstZPCzEORAtPrwd3iz8QAg5A

### 5) Delete post
DELETE http://localhost:3003/posts/92bc1f42-ce2c-4329-8420-72a368034320
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEwMSIsInJvbGUiOiJBRE1JTiIsImlhdCI6MTY2MDM5Mzk2MSwiZXhwIjoxNjYwNDgwMzYxfQ.FwOtXHKx1XXFnMot-CJstZPCzEORAtPrwd3iz8QAg5A

### 6) Like post
POST http://localhost:3003/posts/like/92bc1f42-ce2c-4329-8420-72a368034320
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEwMSIsInJvbGUiOiJBRE1JTiIsImlhdCI6MTY2MDM5Mzk2MSwiZXhwIjoxNjYwNDgwMzYxfQ.FwOtXHKx1XXFnMot-CJstZPCzEORAtPrwd3iz8QAg5A

### 7) Remove Like from post
DELETE http://localhost:3003/posts/like/92bc1f42-ce2c-4329-8420-72a368034320
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEwMSIsInJvbGUiOiJBRE1JTiIsImlhdCI6MTY2MDM5Mzk2MSwiZXhwIjoxNjYwNDgwMzYxfQ.FwOtXHKx1XXFnMot-CJstZPCzEORAtPrwd3iz8QAg5A
9 changes: 9 additions & 0 deletions MODULO 5/Labook/src/business/PingBusiness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export class PingBusiness {
public ping = async () => {
const response = {
message: "Pong!"
}

return response
}
}
184 changes: 184 additions & 0 deletions MODULO 5/Labook/src/business/PostBusiness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import { PostDatabase } from "../database/PostDatabase"
import { IAddLikeInputDTO, IAddLikeOutputDTO, ICreatePostInputDTO, ICreatePostOutputDTO, IDeletePostInputDTO, IDeletePostOutputDTO, IGetPostsInputDTO, IGetPostsOutputDTO, ILikeDB, IRemoveLikeInputDTO, IRemoveLikeOutputDTO, Post } from "../models/Post"
import { USER_ROLES } from "../models/User"
import { Authenticator } from "../services/Authenticator"
import { HashManager } from "../services/HashManager"
import { IdGenerator } from "../services/IdGenerator"

export class PostBusiness {
constructor(
private postDatabase: PostDatabase,
private idGenerator: IdGenerator,
private hashManager: HashManager,
private authenticator: Authenticator
) {}

public createPost = async (input: ICreatePostInputDTO) => {
const { token, content } = input

const payload = this.authenticator.getTokenPayload(token)

if (!payload) {
throw new Error("Não autenticado")
}

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

if (content.length < 1) {
throw new Error("Parâmetro 'content' inválido: mínimo de 1 caracteres")
}

const id = this.idGenerator.generate()

const post = new Post(
id,
content,
payload.id
)

await this.postDatabase.createPost(post)

const response: ICreatePostOutputDTO = {
message: "Post criado com sucesso",
post
}

return response
}

public getPosts = async (input: IGetPostsInputDTO) => {
const { token } = input

const payload = this.authenticator.getTokenPayload(token)

if (!payload) {
throw new Error("Não autenticado")
}

const postsDB = await this.postDatabase.getPosts()

const posts = postsDB.map(postDB => {
return new Post(
postDB.id,
postDB.content,
postDB.user_id
)
})

for (let post of posts) {
const postId = post.getId()
const likes = await this.postDatabase.getLikes(postId)
post.setLikes(likes)
}

const response: IGetPostsOutputDTO = {
posts
}

return response
}

public deletePost = async (input: IDeletePostInputDTO) => {
const { token, postId } = input

const payload = this.authenticator.getTokenPayload(token)

if (!payload) {
throw new Error("Não autenticado")
}

const postDB = await this.postDatabase.findPostById(postId)

if (!postDB) {
throw new Error("Post não encontrado")
}

if (payload.role === USER_ROLES.NORMAL) {
if (postDB.user_id !== payload.id) {
throw new Error("Sem autorização")
}
}

await this.postDatabase.deletePost(postId)

const response: IDeletePostOutputDTO = {
message: "Post deletado com sucesso"
}

return response
}

public addLike = async (input: IAddLikeInputDTO) => {
const { token, postId } = input

const payload = this.authenticator.getTokenPayload(token)

if (!payload) {
throw new Error("Não autenticado")
}

const postDB = await this.postDatabase.findPostById(postId)

if (!postDB) {
throw new Error("Post não encontrado")
}

const isAlreadyLiked = await this.postDatabase.findLike(
postId,
payload.id
)

if (isAlreadyLiked) {
throw new Error("Já deu like")
}

const likeDB: ILikeDB = {
id: this.idGenerator.generate(),
post_id: postId,
user_id: payload.id
}

await this.postDatabase.addLike(likeDB)

const response: IAddLikeOutputDTO = {
message: "Like realizado com sucesso"
}

return response
}

public removeLike = async (input: IRemoveLikeInputDTO) => {
const { token, postId } = input

const payload = this.authenticator.getTokenPayload(token)

if (!payload) {
throw new Error("Não autenticado")
}

const postDB = await this.postDatabase.findPostById(postId)

if (!postDB) {
throw new Error("Post não encontrado")
}

const isAlreadyLiked = await this.postDatabase.findLike(
postId,
payload.id
)

if (!isAlreadyLiked) {
throw new Error("Ainda não deu like")
}

await this.postDatabase.removeLike(postId, payload.id)

const response: IRemoveLikeOutputDTO = {
message: "Like removido com sucesso"
}

return response
}
}
Loading