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 Back-end/modulo2/MODULO3/testes-backend/.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 Back-end/modulo2/MODULO3/testes-backend/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"],
};
34 changes: 34 additions & 0 deletions Back-end/modulo2/MODULO3/testes-backend/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": "jest --watchAll",
"start": "tsc && node --inspect ./build/src/index.js",
"dev": " ts-node-dev ./src/index.ts"
},
"author": "Labenu",
"license": "ISC",
"dependencies": {
"@types/knex": "^0.16.1",
"bcryptjs": "^2.4.3",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"knex": "^2.3.0",
"mysql": "^2.18.1",
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/bcryptjs": "^2.4.2",
"@types/express": "^4.17.13",
"@types/jest": "^28.1.4",
"@types/jsonwebtoken": "^8.5.9",
"@types/uuid": "^7.0.3",
"jest": "^28.1.2",
"ts-jest": "^28.0.5",
"ts-node-dev": "^2.0.0",
"typescript": "^4.7.1"
}
}
Binary file not shown.
18 changes: 18 additions & 0 deletions Back-end/modulo2/MODULO3/testes-backend/src/business/Ports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { AuthenticationData } from "../services/tokenGenerator";

export interface IHashGenerator {
hash(s: string): Promise<any>
compareHash(s: string, hash: string): Promise<boolean>
}

export interface IIDGenerator {
generate(): string
}

export interface ITokenGenerator {
generate(input: AuthenticationData): string
verify(token: string): AuthenticationData
}



Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { CustomError } from "../errors/CustomError";
import { User, stringToUserRole } from "../model/User";
import { IHashGenerator, IIDGenerator, ITokenGenerator } from "./Ports";
import { UserRepository } from "./UserRepository";


export class UserBusiness {
constructor(
private userDatabase: UserRepository,
private hashGenerator: IHashGenerator,
private idGenerator: IIDGenerator,
private tokenGenerator: ITokenGenerator
){}

public async signup(
name: string,
email: string,
password: string,
role: string
) {
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();

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

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

const accessToken = this.tokenGenerator.generate({
id,
role,
});
return { accessToken };
} catch (error:any) {
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:any) {
throw new CustomError(error.statusCode, error.message)
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { User } from "../model/User";

export interface UserRepository {
createUser(user: User): Promise<void>;
getUserByEmail(email: string): Promise<User | undefined>;
getUserById(id: string): Promise<User | undefined>;
getAllUsers(): Promise<User[]>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Request, Response } from "express";
import { UserBusiness } from "../business/UserBusiness";


export class UserController {
constructor(
private userBusiness: UserBusiness
){}

public async signup(req: Request, res: Response) {
try {
const { name, role, email, password } = req.body
const result = await this.userBusiness.signup(
name,
email,
password,
role
);
res.status(200).send(result);
} catch (error:any) {
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 this.userBusiness.login(email, password);
res.status(200).send(result);
} catch (error:any) {
const { statusCode, message } = error
res.status(statusCode || 400).send({ message });
}
}
}

23 changes: 23 additions & 0 deletions Back-end/modulo2/MODULO3/testes-backend/src/data/BaseDatabase.ts
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({
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();
}
}
75 changes: 75 additions & 0 deletions Back-end/modulo2/MODULO3/testes-backend/src/data/UserDatabase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import BaseDataBase from "./BaseDatabase";
import { User } from "../model/User";
import { UserRepository } from "../business/UserRepository";

export class UserDatabase extends BaseDataBase implements UserRepository {

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:any) {
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:any) {
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:any) {
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:any) {
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);
}
}
18 changes: 18 additions & 0 deletions Back-end/modulo2/MODULO3/testes-backend/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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 Back-end/modulo2/MODULO3/testes-backend/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",
}
Loading