Skip to content

Commit b0c3b60

Browse files
author
Pablo Henrique
committed
user module
1 parent 2daa905 commit b0c3b60

19 files changed

+1413
-22
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,19 @@ nodemon -D
1818

1919
Criando setup Ininical - Referencias.
2020
https://dev.to/melquisedecfelipe/configurando-eslint-no-node-com-express-e-typescript-58p9
21+
22+
23+
24+
- Recursos nescessários na api
25+
26+
27+
- Usuário
28+
[ ] Cadastrar novo usuário
29+
[ ] Efeturar login e retornar token de acesso
30+
31+
- PIX
32+
[ ] Efetuar solicitação de PIX
33+
[ ] Receber PIX
34+
35+
Regras:
36+
- quando receber um pix, salvar na tabela de transação

docker-compose.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: '3.1'
2+
3+
services:
4+
db:
5+
container_name: dio
6+
image: postgres
7+
restart: always
8+
ports:
9+
- 5432:5432
10+
environment:
11+
POSTGRES_USER: admin
12+
POSTGRES_PASSWORD: dio-inter
13+
POSTGRES_DB: inter

ormconfig.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name":"default",
3+
"type": "postgres",
4+
"host": "localhost",
5+
"port": 5432,
6+
"username": "admin",
7+
"password": "dio-inter",
8+
"database": "inter",
9+
"entities": ["src/entity/*.ts"],
10+
"logging": false,
11+
"synchronize": true
12+
}

package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,21 @@
1010
"author": "",
1111
"license": "ISC",
1212
"dependencies": {
13+
"@types/cors": "^2.8.12",
14+
"cors": "^2.8.5",
1315
"eslint": "^8.3.0",
14-
"express": "^4.17.1"
16+
"express": "^4.17.1",
17+
"express-async-errors": "^3.1.1",
18+
"express-jwt": "^6.1.0",
19+
"jsonwebtoken": "^8.5.1",
20+
"nodemon": "^2.0.15",
21+
"postgre": "^0.1.8",
22+
"reflect-metadata": "^0.1.13",
23+
"typeorm": "^0.2.41"
1524
},
1625
"devDependencies": {
1726
"@types/express": "^4.17.13",
27+
"@types/jsonwebtoken": "^8.5.6",
1828
"@types/node": "^16.11.9",
1929
"@typescript-eslint/eslint-plugin": "^5.4.0",
2030
"@typescript-eslint/parser": "^5.4.0",

src/@types/express.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare namespace Express {
2+
export interface Request {
3+
user: {
4+
id: string;
5+
};
6+
}
7+
}

src/config/auth.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
export default {
3+
jwt: {
4+
secret: process.env.APP_SECRET || 'default',
5+
expiresIn: '14d',
6+
},
7+
};

src/entity/User.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {Entity, Column, PrimaryGeneratedColumn} from "typeorm";
2+
3+
@Entity()
4+
export class User {
5+
6+
@PrimaryGeneratedColumn('uuid')
7+
id: string;
8+
9+
@Column()
10+
firstName: string;
11+
12+
@Column()
13+
lastName: string;
14+
15+
@Column()
16+
accountNumber: number;
17+
18+
@Column()
19+
accountDigit: number;
20+
21+
@Column()
22+
wallet: number;
23+
24+
@Column()
25+
email: string;
26+
27+
@Column()
28+
password: string;
29+
30+
}

src/index.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
1+
2+
import 'express-async-errors';
13
import express from 'express';
4+
import { createConnection } from 'typeorm';
5+
import cors from 'cors';
26

3-
const app = express();
4-
const PORT = 3333;
7+
import {globalErrors} from './middlewares/globalErros'
8+
import routes from './routes';
59

6-
app.get('/', (req, res) => res.send('Express + TypeScript Server'));
10+
createConnection().then(connection => {
11+
const app = express();
12+
const PORT = 3333;
13+
14+
app.use(cors())
15+
app.use(express.json())
16+
app.use(routes);
717

8-
app.listen(PORT, () => {
9-
console.log(`⚡️[server]: Server is running at http://localhost:${PORT}`);
18+
app.use(globalErrors);
19+
20+
app.listen(PORT, () => {
21+
console.log(`⚡️[server]: Server is running at http://localhost:${PORT}`);
22+
});
23+
}).catch(() => {
24+
console.log("Unable to connect to the database")
1025
});

src/middlewares/globalErros.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Request, Response, NextFunction } from 'express'
2+
import AppError from '../shared/error/AppError'
3+
4+
function globalErrors(err: Error, request: Request, response: Response, next: NextFunction) {
5+
6+
if (err instanceof AppError) {
7+
response.status(err.statusCode).json({
8+
status: 'error',
9+
message: err.message,
10+
data: err?.data
11+
});
12+
}
13+
14+
console.error(err);
15+
16+
return response.status(500).json({
17+
status: 'error',
18+
message: 'Internal server error'
19+
});
20+
21+
}
22+
23+
export { globalErrors };

src/middlewares/userAuthenticated.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Request, Response, NextFunction } from 'express';
2+
import { verify } from 'jsonwebtoken';
3+
import authConfig from '../config/auth';
4+
5+
import AppError from '../shared/error/AppError';
6+
7+
interface ITokenPlayload {
8+
iat: number;
9+
exp: number;
10+
sub: string;
11+
}
12+
13+
export default function ensureAuthenticated(
14+
req: Request,
15+
res: Response,
16+
next: NextFunction,
17+
): void {
18+
// Validação do token JWT
19+
20+
const authHeader = req.headers.authorization;
21+
22+
if (!authHeader) {
23+
throw new AppError('Não foi enviado o JWT', 401);
24+
}
25+
26+
const [, token] = authHeader.split(' ');
27+
28+
try {
29+
const decoded = verify(token, authConfig.jwt.secret);
30+
31+
const { sub } = decoded as ITokenPlayload;
32+
33+
req.user = {
34+
id: sub,
35+
};
36+
37+
return next();
38+
} catch {
39+
throw new AppError('token JWT inválido', 401);
40+
}
41+
}
42+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface UserSignIn {
2+
email: string;
3+
password: string;
4+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface UserSignUp {
2+
firstName: string;
3+
lastName: string;
4+
email: string;
5+
password: string;
6+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Request, Response} from 'express';
2+
3+
import UserService from './user.service';
4+
5+
export default class UserController {
6+
7+
8+
async signin (req: Request, res: Response) {
9+
const {email, password} = req.body;
10+
const userService = new UserService();
11+
const users = await userService.signin({email, password});
12+
return res.status(200).send(users)
13+
}
14+
15+
async signup (req: Request, res: Response) {
16+
const userService = new UserService();
17+
const users = await userService.signup(req.body);
18+
return res.status(201).send(users)
19+
}
20+
}

src/resources/user/user.service.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import {getRepository} from "typeorm"
2+
import { sign } from 'jsonwebtoken';
3+
import {User} from '../../entity/User';
4+
import AppError from '../../shared/error/AppError';
5+
import authConfig from '../../config/auth';
6+
7+
import {UserSignIn} from './dtos/user.signin.dtos'
8+
import {UserSignUp} from './dtos/user.signup.dtos'
9+
10+
export default class UserService {
11+
12+
13+
async signin(user: UserSignIn) {
14+
const userRepository = getRepository(User);
15+
const existUser = await userRepository.findOne({where: {email: user.email, password: user.password}})
16+
17+
if(!existUser){
18+
throw new AppError('Usuário não encontrato', 401);
19+
}
20+
21+
22+
const { secret, expiresIn } = authConfig.jwt;
23+
24+
const token = sign({
25+
firstName: existUser.firstName,
26+
lastName: existUser.lastName,
27+
accountNumber: existUser.accountNumber,
28+
accountDigit: existUser.accountDigit,
29+
wallet: existUser.wallet
30+
}, secret, {
31+
subject: existUser.id,
32+
expiresIn,
33+
});
34+
35+
const { password, ...rest} = existUser
36+
37+
return {rest, token}
38+
}
39+
40+
async signup(user: UserSignUp) {
41+
const userRepository = getRepository(User);
42+
43+
const existUser = await userRepository.findOne({where: {email: user.email}})
44+
45+
if(existUser){
46+
throw new AppError('Já existe um usuário cadastrado com esse email', 401);
47+
}
48+
49+
const userData = {
50+
...user,
51+
wallet: 0,
52+
accountNumber: Math.floor(Math.random() * 999999),
53+
accountDigit: Math.floor(Math.random() * 99)
54+
}
55+
56+
const userCreate = await userRepository.save(userData);
57+
58+
const { secret, expiresIn } = authConfig.jwt;
59+
60+
const token = sign({
61+
firstName: user.firstName,
62+
lastName: user.lastName,
63+
}, secret, {
64+
subject: userCreate.id,
65+
expiresIn,
66+
});
67+
68+
69+
return {userCreate, token};
70+
}
71+
}

src/routes/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Router } from 'express';
2+
import useRouter from './user.routes';
3+
4+
5+
const routes = Router();
6+
7+
routes.use('/user', useRouter);
8+
9+
export default routes;

src/routes/user.routes.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Router } from 'express';
2+
import UserController from '../resources/user/user.controllers';
3+
4+
const useRouter = Router();
5+
const userController = new UserController();
6+
7+
useRouter.post('/signin', userController.signin)
8+
useRouter.post('/signup', userController.signup)
9+
10+
export default useRouter;

src/shared/error/AppError.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
class AppError {
3+
public readonly message: string;
4+
public readonly statusCode: number;
5+
public readonly data?: any
6+
7+
constructor(message: string, statusCode = 400, data?: any) {
8+
this.message = message;
9+
this.statusCode = statusCode;
10+
this.data = data;
11+
}
12+
}
13+
14+
export default AppError;

tsconfig.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
"rootDir": "./src",
66
"outDir": "./build",
77
"esModuleInterop": true,
8-
"strict": true
8+
"moduleResolution": "node",
9+
"noImplicitReturns": false,
10+
"strict": true,
11+
"emitDecoratorMetadata": true,
12+
"strictPropertyInitialization": false,
13+
"experimentalDecorators": true
914
}
10-
}
15+
}

0 commit comments

Comments
 (0)