-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PR de correção #15
base: correcao-projeto
Are you sure you want to change the base?
PR de correção #15
Changes from 31 commits
3b0dc6e
a68c4ce
5b0f011
c81b76f
7dfd53a
7912a41
5ea98ca
a48f927
914eb2c
6ee86c3
6256396
69c9f3d
7c9f2ec
62886ab
0f42efd
a0213cd
597c0d6
559f4e0
7ec92a6
b115526
8c9137a
4d1d736
1942bd7
ad3a93e
edb9631
5e6f7d9
33f0fe6
0bbad38
1f2ca66
4bb83d8
89e8bd9
9bf9fbd
368cad5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/node_modules | ||
.env |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{ | ||
"name": "julian-labook2", | ||
"version": "1.0.0", | ||
"description": "backend de rede social desenvolvido como projeto da semana 18", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"start": "clear && ts-node ./src/index.ts" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/future4code/julian-labook2.git" | ||
}, | ||
"author": "Osman Rodrigues, Wellington Cardoso e Wagner Cardoso", | ||
"license": "ISC", | ||
"bugs": { | ||
"url": "https://github.com/future4code/julian-labook2/issues" | ||
}, | ||
"homepage": "https://github.com/future4code/julian-labook2#readme", | ||
"dependencies": { | ||
"@types/bcrypt": "^3.0.0", | ||
"@types/bcryptjs": "^2.4.2", | ||
"@types/express": "^4.17.0", | ||
"@types/jsonwebtoken": "^8.5.0", | ||
"@types/knex": "^0.16.1", | ||
"@types/moment": "^2.13.0", | ||
"@types/node": "^14.0.23", | ||
"@types/uuid": "^8.0.0", | ||
"bcryptjs": "^2.4.3", | ||
"dotenv": "^8.2.0", | ||
"express": "^4.17.0", | ||
"jsonwebtoken": "^8.5.1", | ||
"knex": "^0.21.2", | ||
"moment": "^2.27.0", | ||
"mysql": "^2.18.1", | ||
"ts-node": "^8.10.2", | ||
"typescript": "^3.9.7", | ||
"uuid": "^8.2.0" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import {PostsDatabase} from '../data/PostsDatabase'; | ||
import {IdGenerator} from '../services/utils/IdGenerator'; | ||
import {CustomError} from '../error/CustomError'; | ||
|
||
export class PostsBusiness{ | ||
|
||
async createPost( | ||
img_url: string, | ||
type?:string, | ||
create_at?: string, | ||
description?:string | ||
){ | ||
//TODO: validar criação de post mediante access token | ||
if(! img_url || img_url.trim() === ''){ | ||
throw new CustomError(416,'Missing post image url.'); | ||
}else if(! img_url.includes('http')){ | ||
throw new CustomError(406,'Invalid post image url.'); | ||
}; | ||
Comment on lines
+14
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gostei da validação aqui! |
||
|
||
const usePostsDb = new PostsDatabase(); | ||
const idGen = new IdGenerator(); | ||
|
||
await usePostsDb.createPost({ | ||
id: idGen.generate(), | ||
img_url, | ||
type, | ||
create_at, | ||
description | ||
}); | ||
}; | ||
|
||
Comment on lines
+22
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. O endpoint realmente acabou por criar o post sem gravar o autor do post There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Macacos me mordam! Eu lembrei de ter arrumado o campo na tabela pra receber essa info, mas esqueci de mudar na query! haha |
||
async getPostById(id:string): Promise<any>{ | ||
//TODO: validar consulta de post mediante access token | ||
if(id.length != 36){ | ||
throw new CustomError(416,'Invalid post id.'); | ||
}; | ||
try{ | ||
const usePostsDb = new PostsDatabase(); | ||
const dbResponse = await usePostsDb.getPostById(id); | ||
|
||
if(! dbResponse){ | ||
throw new CustomError(416,'Post not found.'); | ||
}; | ||
|
||
return dbResponse; | ||
}catch(e){ | ||
throw new CustomError(400, e.message); | ||
}; | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { UserDatabase } from "../data/UserDatabase"; | ||
import { IdGenerator } from "../services/utils/IdGenerator"; | ||
import {HashManager} from '../services/utils/HashManager'; | ||
import {Authenticator} from '../services/utils/Authenticator'; | ||
import {CustomError} from '../error/CustomError'; | ||
|
||
export class UserBusiness{ | ||
|
||
public async signup(name: string, email: string, password: string, role:string){ | ||
|
||
try { | ||
const idGenerator = new IdGenerator(); | ||
const id:string = idGenerator.generate(); | ||
|
||
const useHashed = new HashManager(); | ||
const passwordHashed = await useHashed.hash(password); | ||
|
||
const userDatabase = new UserDatabase(); | ||
await userDatabase.signup(id, name, email, passwordHashed, role) | ||
|
||
const autheticated = new Authenticator(); | ||
const token = autheticated.generateToken({ id, name, email, role },process.env.ACC_TOKEN_EXPIRES_IN); | ||
|
||
|
||
return { accessToken: token } | ||
|
||
} catch (error) { | ||
throw new Error(error.message) | ||
} | ||
}; | ||
|
||
public async login(email:string, password:string){ | ||
const userDatabase = new UserDatabase(); | ||
const userInfo = await userDatabase.getByEmail(email); | ||
|
||
const checkedPassword = new HashManager(); | ||
const comparePassword = await checkedPassword.checkHash(userInfo.password ,password); | ||
|
||
const autheticated = new Authenticator(); | ||
const token = autheticated.generateToken( userInfo ,process.env.ACC_TOKEN_EXPIRES_IN); | ||
|
||
return comparePassword && token; | ||
|
||
}; | ||
|
||
public async makeFriendship(friendId: string, token: string){ | ||
//TODO: não permitir amizades duplicadas ou com o mesmo id de usuário e amigo | ||
if(!token){ | ||
throw new CustomError(416, 'Token de acesso ausente.') | ||
}; | ||
|
||
const useAuthenticator = new Authenticator(); | ||
const useUserDb = new UserDatabase(); | ||
|
||
const userTokenInfos = useAuthenticator.getData(token); | ||
const userDbInfos = await useUserDb.getById(userTokenInfos.id); | ||
|
||
if(!userDbInfos){ | ||
throw new CustomError(404, 'Usuário não encontrado.'); | ||
}; | ||
|
||
try{ | ||
await useUserDb.createFriendship(userTokenInfos.id, friendId); | ||
}catch(e){ | ||
throw new CustomError(400, e.message) | ||
}; | ||
}; | ||
|
||
public async deleteFriendship(friendId: string, token: string){ | ||
if(!token){ | ||
throw new CustomError(416, 'Token de acesso ausente.') | ||
}; | ||
|
||
const useAuthenticator = new Authenticator(); | ||
const useUserDb = new UserDatabase(); | ||
|
||
const userTokenInfos = useAuthenticator.getData(token); | ||
const userDbInfos = await useUserDb.getById(userTokenInfos.id); | ||
|
||
if(!userDbInfos){ | ||
throw new CustomError(404, 'Usuário não encontrado.'); | ||
}; | ||
|
||
try{ | ||
const useUserDb = new UserDatabase(); | ||
await useUserDb.deleteFriendship(userTokenInfos.id, friendId); | ||
}catch(e){ | ||
throw new CustomError(400, e.message) | ||
}; | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Request, Response } from 'express'; | ||
import { Authenticator } from '../services/utils/Authenticator'; | ||
import { PostsDatabase } from '../data/PostsDatabase'; | ||
|
||
export class FeedController { | ||
async showFeed(request: Request, response: Response) { | ||
try { | ||
const { authorization } = request.headers; | ||
const { type } = request.query; | ||
const auth = new Authenticator(); | ||
const payload = auth.getData(authorization); | ||
const postsDb = new PostsDatabase(); | ||
|
||
const feedData = await postsDb.showFeed(payload.id); | ||
|
||
await postsDb.destroyConnection(); | ||
|
||
return response.send({ feed: feedData }); | ||
} catch(e) { | ||
response.status(400).send({ error: e.message}) | ||
} | ||
} | ||
|
||
async showFeedByType(request: Request, response: Response) { | ||
try { | ||
const { authorization } = request.headers; | ||
const { type } = request.query; | ||
const auth = new Authenticator(); | ||
auth.getData(authorization); | ||
const postsDb = new PostsDatabase(); | ||
|
||
const feedData = await postsDb.showFeedByType(type as string); | ||
|
||
await postsDb.destroyConnection(); | ||
|
||
return response.send({ feed: feedData }); | ||
} catch(e) { | ||
response.status(400).send({ error: e.message }); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import {Request, Response} from 'express'; | ||
import {PostsBusiness} from '../business/PostsBusiness'; | ||
import {PostsDatabase} from '../data/PostsDatabase'; | ||
|
||
import moment from 'moment'; | ||
|
||
export class PostsController { | ||
async createPost(req: Request, res: Response){ | ||
try{ | ||
const body = req.body; | ||
await new PostsBusiness().createPost( | ||
body.img_url, body.type, body.create_at, body.description | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uma possibilidade aqui é deixar a criação das datas automática! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Eu passei por precaução pq tinha uma validação no business e um default pra o campo de data lá no banco atribuir a curdate caso não fosse passada uma data. É melhor prevenir do que remediar! haha |
||
); | ||
|
||
res.send({message: `Post created successfully!`}).status(200); | ||
|
||
await new PostsDatabase().destroyConnection(); | ||
}catch(e){ | ||
res.status(400).send({error: e.message}); | ||
} | ||
}; | ||
async getPostById(req: Request, res: Response): Promise<void>{ | ||
try{ | ||
const postId = String(req.params.id); | ||
const response = await new PostsBusiness().getPostById(postId); | ||
|
||
res.send({post:{ | ||
...response, create_at: moment(response.create_at, 'YYYY/MM/DD').format('DD/MM/YYYY') | ||
}}).status(200); | ||
}catch(e){ | ||
res.status(400).send({error: e.message}); | ||
}; | ||
}; | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { Request, Response } from "express"; | ||
import { UserBusiness } from "../business/UserBusiness"; | ||
|
||
export class UserController { | ||
|
||
async signup(req: Request, res: Response) { | ||
const userBusiness: UserBusiness = new UserBusiness(); | ||
|
||
try { | ||
const name = req.body.name; | ||
const email = req.body.email; | ||
const password = req.body.password; | ||
const role = req.body.role; | ||
|
||
const result = await userBusiness.signup(name, email, password, role); | ||
|
||
res.status(200).send({ message: "Usuário criado com sucesso", result }); | ||
|
||
} catch (err) { | ||
res.status(400).send({ error: err.message }); | ||
} | ||
}; | ||
|
||
/* TODO validações de senha e email */ | ||
|
||
async login(req: Request, res: Response) { | ||
const userBusiness: UserBusiness = new UserBusiness(); | ||
|
||
try { | ||
const body = req.body | ||
|
||
const requestInfo = await userBusiness.login(body.email, body.password); | ||
|
||
|
||
if(requestInfo){ | ||
res.status(200).send({accessToken: requestInfo }) | ||
} | ||
|
||
} catch (error) { | ||
res.status(400).send({ error: error.message }); | ||
} | ||
Comment on lines
+31
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Temos um probleminha aqui. Se a senha estiver incorreta nunca caímos no catch e o endpoint carrega para sempre |
||
}; | ||
|
||
async makeFriendship(req: Request, res: Response){ | ||
const headersToken = req.headers.authorization; | ||
const useUserBusiness: UserBusiness = new UserBusiness(); | ||
try { | ||
const body = req.body | ||
await useUserBusiness.makeFriendship(body.friendId, headersToken); | ||
|
||
res.status(200).send({message: 'Amizade criada com sucesso!'}) | ||
} catch (error) { | ||
res.status(400).send({ error: error.message }); | ||
} | ||
}; | ||
|
||
async deleteFriendship(req: Request, res: Response){ | ||
const headersToken = req.headers.authorization; | ||
const useUserBusiness: UserBusiness = new UserBusiness(); | ||
|
||
try { | ||
const body = req.body | ||
await useUserBusiness.deleteFriendship(body.friendId, headersToken); | ||
|
||
res.status(200).send({message: 'Amizade desfeita com sucesso!'}) | ||
} catch (error) { | ||
res.status(400).send({ error: error.message }); | ||
} | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import knex from "knex" | ||
import Knex from "knex" | ||
|
||
export abstract class BaseDatabase{ | ||
private static connection: Knex | null = null; | ||
|
||
public getConnection(tableName?:string): Knex{ | ||
if(!BaseDatabase.connection){ | ||
BaseDatabase.connection = knex({ | ||
client: "mysql", | ||
connection: { | ||
host: process.env.DB_HOST, | ||
port: 3306, | ||
user: process.env.DB_USER, | ||
password: process.env.DB_PASSWORD, | ||
database: process.env.DB_NAME | ||
} | ||
}) | ||
} | ||
|
||
return BaseDatabase.connection | ||
}; | ||
|
||
public async destroyConnection() { | ||
await BaseDatabase.connection.destroy() | ||
BaseDatabase.connection = null; | ||
}; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lembrem de remover os comentários depois!