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
Binary file not shown.
6 changes: 6 additions & 0 deletions semana21/aula64/template-testes-backend-feito/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
build/
.vscode/

.env
.rest
8 changes: 8 additions & 0 deletions semana21/aula64/template-testes-backend-feito/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
roots: ["<rootDir>/tests"],
transform: {
"^.+\\.tsx?$": "ts-jest",
},
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
};
7,119 changes: 7,119 additions & 0 deletions semana21/aula64/template-testes-backend-feito/package-lock.json

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions semana21/aula64/template-testes-backend-feito/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "testes-no-backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "clear && echo \"Running tests...\" && jest",
"start": "tsc && node --inspect ./build/src/index.js",
"dev": " ts-node-dev ./src/index.ts"
},
"author": "Labenu",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"knex": "^0.21.1",
"mysql": "^2.18.1",
"uuid": "^8.0.0"
},
"devDependencies": {
"jest": "^26.0.1",
"ts-jest": "^26.1.0",
"typescript": "^3.9.2",
"ts-node-dev": "^1.0.0-pre.44",
"@types/bcryptjs": "^2.4.2",
"@types/express": "^4.17.6",
"@types/jest": "^25.2.3",
"@types/jsonwebtoken": "^8.5.0",
"@types/knex": "^0.16.1",
"@types/uuid": "^7.0.3"
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { CustomError } from "../errors/CustomError";
import { User, stringToUserRole } from "../model/User";
import { UserDatabase } from "../data/UserDatabase";
import { HashGenerator } from "../services/hashGenerator";
import { IdGenerator } from "../services/idGenerator";
import { TokenGenerator } from "../services/tokenGenerator";

export class UserBusiness {
constructor(
private idGenerator: IdGenerator,
private hashGenerator: HashGenerator,
private tokenGenerator: TokenGenerator,
private userDatabase: UserDatabase
) {}

public async signup(
name: string,
email: string,
password: string,
role: string
): Promise<object> {
try {
if (!name || !email || !password || !role) {
throw new CustomError(422, "Missing input");
}

if (email.indexOf("@") === -1) {
throw new CustomError(422, "Invalid email");
}

if (password.length < 6) {
throw new CustomError(422, "Invalid password");
}

const id = this.idGenerator.generate(); // dependecia

const cypherPassword = await this.hashGenerator.hash(password); // dependecia

await this.userDatabase.createUser(
new User(id, name, email, cypherPassword, stringToUserRole(role))
); // dependecia

const accessToken = this.tokenGenerator.generate({
id,
role,
}); // dependecia

return { accessToken };
} catch (error) {
if (error.message.includes("key 'email'")) {
throw new CustomError(409, "Email already in use");
}

throw new CustomError(error.statusCode, error.message);
}
}

public async login(email: string, password: string) {
try {
if (!email || !password) {
throw new CustomError(422, "Missing input");
}

const user = await this.userDatabase.getUserByEmail(email);

if (!user) {
throw new CustomError(401, "Invalid credentials");
}

const isPasswordCorrect = await this.hashGenerator.compareHash(
password,
user.getPassword()
);

if (!isPasswordCorrect) {
throw new CustomError(401, "Invalid credentials");
}

const accessToken = this.tokenGenerator.generate({
id: user.getId(),
role: user.getRole(),
});

return { accessToken };
} catch (error) {
throw new CustomError(error.statusCode, error.message);
}
}

public async getUserById(id: string): Promise<User | undefined> {
switch (id) {
case "id_mock_1":
return userMock;
case "id_mock_2":
return userMock2;
default:
undefined;
}
}
}

export default new UserBusiness(
new IdGenerator(),
new HashGenerator(),
new TokenGenerator(),
new UserDatabase()
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Request, Response } from "express";
import { UserBusiness } from "../business/UserBusiness";


export class UserController {

public async signup(req: Request, res: Response) {
try {
const { name, role, email, password } = req.body
const result = await UserBusiness.signup(
name,
email,
password,
role
);
res.status(200).send(result);
} catch (error) {
const { statusCode, message } = error
res.status(statusCode || 400).send({ message });
}
}

public async login(req: Request, res: Response) {
try {
const { email, password } = req.body
const result = await userBusiness.login(email, password);
res.status(200).send(result);
} catch (error) {
const { statusCode, message } = error
res.status(statusCode || 400).send({ message });
}
}
}

export default new UserController()
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import dotenv from "dotenv";
import knex from "knex";

dotenv.config();

export default class BaseDataBase {

protected static connection: knex = knex({
client: "mysql",
connection: {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_SCHEMA,
port: 3306,
multipleStatements: true
},
});

public static async destroyConnection(): Promise<void> {
await BaseDataBase.connection.destroy();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import BaseDataBase from "./BaseDatabase";
import { User } from "../model/User";

export class UserDatabase extends BaseDataBase {
protected tableName: string = "INSIRA AQUI O NOME DA SUA TABELA DE USUÁRIOS";

private toModel(dbModel?: any): User | undefined {
return (
dbModel &&
new User(
dbModel.id,
dbModel.name,
dbModel.email,
dbModel.password,
dbModel.role
)
);
}

public async createUser(user: User): Promise<void> {
try {
await BaseDataBase.connection.raw(`
INSERT INTO ${this.tableName} (id, name, email, password, role)
VALUES (
'${user.getId()}',
'${user.getName()}',
'${user.getEmail()}',
'${user.getPassword()}',
'${user.getRole()}'
)`);
} catch (error) {
throw new Error(error.sqlMessage || error.message);
}
}

public async getUserByEmail(email: string): Promise<User | undefined> {
try {
const result = await BaseDataBase.connection.raw(`
SELECT * from ${this.tableName} WHERE email = '${email}'
`);
return this.toModel(result[0][0]);
} catch (error) {
throw new Error(error.sqlMessage || error.message);
}
}

public async getUserById(id: string): Promise<User | undefined> {
try {
const result = await BaseDataBase.connection.raw(`
SELECT * from ${this.tableName} WHERE id = '${id}'
`);
return this.toModel(result[0][0]);
} catch (error) {
throw new Error(error.sqlMessage || error.message);
}
}

public async getAllUsers(): Promise<User[]> {
try {
const result = await BaseDataBase.connection.raw(`
SELECT * from ${this.tableName}
`);
return result[0].map((res: any) => {
return this.toModel(res);
});
} catch (error) {
throw new Error(error.sqlMessage || error.message);
}
}
}

export default new UserDatabase();
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export class CustomError extends Error {
constructor(
public statusCode: number,
message: string
) {
super(message);
}
}
21 changes: 21 additions & 0 deletions semana21/aula64/template-testes-backend-feito/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import express from "express";
import { AddressInfo } from "net";
import { userRouter } from "./router/UserRouter";


const app = express();

app.use(express.json());

app.use("/users", userRouter);



const server = app.listen(3003, () => {
if (server) {
const address = server.address() as AddressInfo;
console.log(`Servidor rodando em http://localhost:${address.port}`);
} else {
console.error(`Falha ao rodar o servidor.`);
}
});
47 changes: 47 additions & 0 deletions semana21/aula64/template-testes-backend-feito/src/model/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { CustomError } from "../errors/CustomError";

export class User {
constructor(
private id: string,
private name: string,
private email: string,
private password: string,
private role: USER_ROLES
) { }

public getId(): string {
return this.id;
}

public getName(): string {
return this.name;
}

public getEmail(): string {
return this.email;
}

public getPassword(): string {
return this.password;
}

public getRole(): USER_ROLES {
return this.role;
}
}

export const stringToUserRole = (input: string): USER_ROLES => {
switch (input) {
case "NORMAL":
return USER_ROLES.NORMAL;
case "ADMIN":
return USER_ROLES.ADMIN;
default:
throw new CustomError(422, "Invalid user role");
}
};

export enum USER_ROLES {
NORMAL = "NORMAL",
ADMIN = "ADMIN",
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import express from "express";
import userController from "../controller/UserController";

export const userRouter = express.Router();

userRouter.post("/signup", userController.signup);
userRouter.post("/login", userController.login);
Loading