yarn add jsonwebtoken bcryptjs
yarn add @types/jsonwebtoken @types/bcryptjs -D
users
para adicionar campo de senha - 14:45yarn typeorm migration:create -n AlterUsersAddPassword
src/database/migrations/*AterUsersAddPassword.ts
import { MigrationInterface, QueryRunner, TableColumn } from "typeorm";
export class AlterUsersAddPassword1624650506779 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.addColumn(
"users",
new TableColumn({
name: "password",
type: "varchar",
isNullable: true
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn("users", "password")
}
}
yarn typeorm migration:run
Adicionar coluna password
em:
src/entities/User.ts
:
@Column()
password: string;
src/services/CreateUserService.ts
import { hash } from "bcryptjs";
interface IUserRequest {
name: string;
email: string;
admin?: boolean;
password: string;
}
class CreateUserService {
async execute({ name, email, admin = false, password }: IUserRequest) {
// ...
const passwordHash = await hash(password, 8);
const user = usersRepository.create({
name,
email,
admin,
password: passwordHash
});
// ...
}
}
src/controllers/CreateUserController.ts
class CreateUserController {
async handle(request: Request, response: Response) {
const { name, email, admin, password } = request.body;
const createUserService = new CreateUserService();
const user = await createUserService.execute({ name, email, admin, password });
return response.json(user);
}
}
Testa criar um usuário via insomnia e confere no beekeeper se a senha está criptografada.
src/services/AuthenticateUserService.ts
:
import { getCustomRepository } from "typeorm";
import { compare } from "bcryptjs";
import { sign } from "jsonwebtoken";
import { UserRepositories } from "../repositories/UserRepositories";
interface IAuthenticateRequest {
email: string;
password: string;
}
class AuthenticateUserService {
async execute({ email, password }: IAuthenticateRequest) {
const usersRepositories = getCustomRepository(UserRepositories);
const user = await usersRepositories.findOne({
email
});
if (!user) {
throw new Error("Email/Password incorrect");
}
const isPasswordCorrect = await compare(password, user.password);
if (!isPasswordCorrect) {
throw new Error("Email/Password incorrect");
}
const token = sign(
{
email: user.email
},
"cf0ae2f97f7f852f8cdede8ac4ccfc21", // generated with `md5sum`
{
subject: user.id,
expiresIn: "1d"
}
);
return token;
}
}
export { AuthenticateUserService };
src/controllers/AuthenticateUserController.ts
:
import { Request, Response } from "express";
import { AuthenticateUserService } from "../services/AuthenticateUserService";
class AuthenticateUserController {
async handle(request: Request, response: Response) {
const { email, password } = request.body;
const authenticateUserService = new AuthenticateUserService();
const token = await authenticateUserService.execute({
email,
password
});
return response.json(token);
}
}
export { AuthenticateUserController };
src/routes.ts
:
import { AuthenticateUserController } from "./controllers/AuthenticateUserController";
// ...
const authenticateUserController = new AuthenticateUserController;
// ...
router.post("/login", authenticateUserController.handle);
// ...
Testar autenticação via insomnia - 41:40
compliments
- 44:55yarn typeorm migration:create -n CreateCompliments
src/migrations/*.CreateCompliments.ts
:
import { MigrationInterface, QueryRunner, Table } from "typeorm";
export class CreateCompliments1624652706618 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: "compliments",
columns: [
{
name: "id",
type: "uuid",
isPrimary: true
},
{
name: "user_sender",
type: "uuid",
},
{
name: "user_receiver",
type: "uuid",
},
{
name: "tag_id",
type: "uuid"
},
{
name: "message",
type: "varchar"
},
{
name: "created_at",
type: "timestamp",
default: "now()"
}
],
foreignKeys: [
{
name: "FKUserSenderCompliments",
referencedTableName: "users",
referencedColumnNames: ["id"],
columnNames: ["user_sender"],
onDelete: "SET NULL",
onUpdate: "SET NULL"
},
{
name: "FKUserReceiverCompliments",
referencedTableName: "users",
referencedColumnNames: ["id"],
columnNames: ["user_receiver"],
onDelete: "SET NULL",
onUpdate: "SET NULL"
},
{
name: "FKUserSenderCompliments",
referencedTableName: "tags",
referencedColumnNames: ["id"],
columnNames: ["tag_id"],
onDelete: "SET NULL",
onUpdate: "SET NULL"
},
]
})
)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable("compliments");
}
}
yarn typeorm migration:run
Checar no beekeeper se a tabela foi criada corretamente e se as chaves estrangeiras estão devidamente identificadas.
src/entities/Compliment.ts
:
import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, PrimaryColumn } from "typeorm";
import { v4 as uuid } from "uuid";
import { Tag } from "./Tag";
import { User } from "./User";
@Entity("compliments")
class Compliment {
@PrimaryColumn()
readonly id: string;
@Column()
user_sender: string;
@JoinColumn({ name: "user_sender" })
@ManyToOne(() => User)
userSender: User;
@Column()
user_receiver: string;
@JoinColumn({ name: "user_receiver" });
@ManyToOne(() => User)
userReceiver: User;
@Column()
tag_id: string;
@JoinColumn({ name: "tag_id" });
@ManyToOne(() => Tag)
tag: Tag;
@Column()
message: string;
@CreateDateColumn()
created_at: Date;
constructor() {
if (!this.id) {
this.id = uuid();
}
}
}
export { Compliment };
src/repositories/ComplimentsRepositories.ts
import { Repository } from "typeorm";
import { Compliment } from "../entities/Compliment";
class ComplimentsRepositories extends Repository<Compliment> { }
export { ComplimentsRepositories };
src/services/CreateComplimentService.ts
import { getCustomRepository } from "typeorm";
import { ComplimentsRepositories } from "../repositories/ComplimentsRepositories";
import { UserRepositories } from "../repositories/UserRepositories";
interface IComplimentRequest {
tag_id: string;
user_sender: string;
user_receiver: string;
message: string;
}
class CreateComplimentService {
async execute({
tag_id,
user_sender,
user_receiver,
message,
}: IComplimentRequest) {
if (user_sender === user_receiver) {
throw new Error("Incorrect User Receiver");
}
const complimentsRepositories = getCustomRepository(ComplimentsRepositories);
const usersRepositories = getCustomRepository(UserRepositories);
const userReceiverExists = await usersRepositories.findOne(user_receiver);
if (!userReceiverExists) {
throw new Error("User Receiver does not exist!");
}
const compliment = complimentsRepositories.create({
tag_id,
user_sender,
user_receiver,
message
});
await complimentsRepositories.save(compliment);
return compliment;
}
}
export { CreateComplimentService };
src/controllers/CreateComplimentController.ts
:
import { Request, Response } from "express";
import { CreateComplimentService } from "../services/CreateComplimentService";
class CreateComplimentController {
async handle(request: Request, response: Response) {
const { tag_id, user_sender, user_receiver, message } = request.body;
const createComplimentService = new CreateComplimentService();
const compliment = await createComplimentService.execute({
tag_id,
user_sender,
user_receiver,
message
});
return response.json(compliment);
}
}
export { CreateComplimentController };
src/routes.ts
// ...
import { CreateComplimentController } from "./controllers/CreateComplimentController";
// ...
const createComplimentController = new CreateComplimentController();
//...
router.post("/compliments", createComplimentController.handle);
export { router };
Testar a aplicação e tentar criar um elogio via insomnia, acessando o endpoint /compliments
com o seguinte payload:
{
"tag_id": "",
"user_sender": "",
"user_receiver": "",
"message": ""
}
Conferir no beekeeper.
Outros testes:
user_sender === user_receiver
não podeNo src/services/CreateUserService.ts
, definir um valor default para admin
- 1:24:50.
Desta forma ao criar um usuário não precisa enviar "admin": false
no JSON.