#
tokens: 9263/50000 46/46 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── jest.config.ts
├── package.json
├── prisma
│   ├── migrations
│   │   ├── 20220819211355_create_deliveryman
│   │   │   └── migration.sql
│   │   ├── 20220819213758_update_name_deliveryman
│   │   │   └── migration.sql
│   │   ├── 20220819213956_create_clients_table
│   │   │   └── migration.sql
│   │   ├── 20220819214400_create_deliveries_table
│   │   │   └── migration.sql
│   │   ├── 20220819233031_alter_table_deliveries
│   │   │   └── migration.sql
│   │   ├── 20220819233224_alter_endat_deliveries_table
│   │   │   └── migration.sql
│   │   ├── 20220819234017_alter_end_date
│   │   │   └── migration.sql
│   │   └── migration_lock.toml
│   └── schema.prisma
├── src
│   ├── @types
│   │   └── express
│   │       └── index.d.ts
│   ├── database
│   │   ├── prismaClient.ts
│   │   └── repositories
│   │       ├── ClientRepository.ts
│   │       └── interfaces
│   │           └── IClientRepository.ts
│   ├── kafka
│   │   └── producer.ts
│   ├── middlewares
│   │   ├── ensureAuthClient.ts
│   │   └── ensureAuthDeliveryman.ts
│   ├── modules
│   │   ├── account
│   │   │   ├── authenticateClient
│   │   │   │   ├── AuthenticateClientController.ts
│   │   │   │   └── AuthenticateClientUseCase.ts
│   │   │   └── authenticateDeliveryman
│   │   │       ├── AuthenticateDeliverymanController.ts
│   │   │       └── AuthenticateDeliverymanUseCase.ts
│   │   ├── clients
│   │   │   └── useCases
│   │   │       ├── createClient
│   │   │       │   ├── createClient.spec.ts
│   │   │       │   ├── createClientController.ts
│   │   │       │   ├── createClienteUseCase.ts
│   │   │       │   └── index.ts
│   │   │       └── findClientDeliveries
│   │   │           ├── FindClientDeliveries.spec.ts
│   │   │           ├── FindClientDeliveriesController.ts
│   │   │           ├── FindClientDeliveriesUseCase.ts
│   │   │           └── index.ts
│   │   ├── deliveries
│   │   │   ├── updateEndDate
│   │   │   │   ├── UpdateEndDateController.ts
│   │   │   │   └── UpdateEndDateUseCase.ts
│   │   │   └── useCases
│   │   │       ├── createDelivery
│   │   │       │   ├── CreateDeliveryController.ts
│   │   │       │   └── CreateDeliveryUseCase.ts
│   │   │       ├── findAllAvailable
│   │   │       │   ├── FindAllAvailableController.ts
│   │   │       │   └── FindAllAvailableUseCase.ts
│   │   │       └── updateDeliveryman
│   │   │           ├── UpdateDeliverymanController.ts
│   │   │           └── UpdateDeliverymanUseCase.ts
│   │   └── deliveryman
│   │       └── useCases
│   │           ├── createDeliveryman
│   │           │   ├── CreateDeliverymanController.ts
│   │           │   └── CreateDeliverymanUseCase.ts
│   │           └── findAllDeliveries
│   │               ├── FindAllDeliveriesController.ts
│   │               └── FindAllDeliveriesUseCase.ts
│   ├── routes.ts
│   ├── server.ts
│   └── tests
│       └── inMemoryDatabases
│           └── InMemoryClientsRepository.ts
├── tsconfig.json
└── yarn.lock
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
node_modules
# Keep environment variables out of version control
.env

```

--------------------------------------------------------------------------------
/prisma/migrations/20220819234017_alter_end_date/migration.sql:
--------------------------------------------------------------------------------

```sql
-- AlterTable
ALTER TABLE "deliveries" ALTER COLUMN "end_at" DROP DEFAULT;

```

--------------------------------------------------------------------------------
/prisma/migrations/20220819233224_alter_endat_deliveries_table/migration.sql:
--------------------------------------------------------------------------------

```sql
-- AlterTable
ALTER TABLE "deliveries" ALTER COLUMN "end_at" SET DEFAULT CURRENT_TIMESTAMP;

```

--------------------------------------------------------------------------------
/src/database/prismaClient.ts:
--------------------------------------------------------------------------------

```typescript
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient()

export { prisma }
```

--------------------------------------------------------------------------------
/src/@types/express/index.d.ts:
--------------------------------------------------------------------------------

```typescript
declare namespace Express{
  export interface Request{
    id_client: string;
    id_deliveryman: string;
  }
}
```

--------------------------------------------------------------------------------
/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------

```toml
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "sourceMap": true,
    "outDir": "dist",
    "strict": true,
    "lib": ["esnext"],
    "esModuleInterop": true
  }
}
```

--------------------------------------------------------------------------------
/prisma/migrations/20220819213956_create_clients_table/migration.sql:
--------------------------------------------------------------------------------

```sql
-- CreateTable
CREATE TABLE "clients" (
    "id" TEXT NOT NULL,
    "username" TEXT NOT NULL,
    "password" TEXT NOT NULL,

    CONSTRAINT "clients_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "clients_username_key" ON "clients"("username");

```

--------------------------------------------------------------------------------
/prisma/migrations/20220819211355_create_deliveryman/migration.sql:
--------------------------------------------------------------------------------

```sql
-- CreateTable
CREATE TABLE "Deliveryman" (
    "id" TEXT NOT NULL,
    "username" TEXT NOT NULL,
    "password" TEXT NOT NULL,

    CONSTRAINT "Deliveryman_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "Deliveryman_username_key" ON "Deliveryman"("username");

```

--------------------------------------------------------------------------------
/src/modules/deliveries/useCases/findAllAvailable/FindAllAvailableUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { prisma } from "../../../../database/prismaClient";

export class FindAllAvailableUseCase{
  async execute(){
    const deliveries = await prisma.deliveries.findMany({
      where: {
        end_at: null,
        id_deliveryman: null,
      }
    })

    return deliveries
  }
}
```

--------------------------------------------------------------------------------
/src/database/repositories/interfaces/IClientRepository.ts:
--------------------------------------------------------------------------------

```typescript
import { Clients } from "@prisma/client";

export interface CreateRequestProps{
  username: string;
  password: string
}

export interface FindRequestProps{
  id_client: string;
}

export interface IClientRepository {
  create({ username, password }: CreateRequestProps): Promise<Clients>
  find({ id_client }: FindRequestProps): Promise<Clients[]>
}
```

--------------------------------------------------------------------------------
/src/modules/deliveries/useCases/createDelivery/CreateDeliveryUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { prisma } from "../../../../database/prismaClient";

interface ICreateDelivery{
  item_name: string;
  id_client: string;
}

export class CreateDeliveryUseCase{
  async execute({ item_name, id_client }: ICreateDelivery){

    const delivery = await prisma.deliveries.create({
      data: {
        item_name,
        id_client,
      }
    })

    return delivery
  }
}
```

--------------------------------------------------------------------------------
/src/modules/deliveries/updateEndDate/UpdateEndDateUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { prisma } from "../../../database/prismaClient";

interface IUpdateEndDate{
  id_delivery: string;
}

export class UpdateEndDateUseCase{
  async execute({ id_delivery }: IUpdateEndDate){
    const delivery = await prisma.deliveries.update({
      where: {
        id: id_delivery,
      },
      data: {
        end_at: new Date()
      }
    })

    return delivery
  }
}
```

--------------------------------------------------------------------------------
/src/modules/deliveries/useCases/findAllAvailable/FindAllAvailableController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { FindAllAvailableUseCase } from "./findAllAvailableUseCase";



export class FindAllAvailableController{
  async handle(request: Request, response: Response){
    const findAllAvailableUseCase = new FindAllAvailableUseCase()

    const deliveries = await findAllAvailableUseCase.execute()

    return response.json(deliveries)
  }
}
```

--------------------------------------------------------------------------------
/prisma/migrations/20220819233031_alter_table_deliveries/migration.sql:
--------------------------------------------------------------------------------

```sql
-- DropForeignKey
ALTER TABLE "deliveries" DROP CONSTRAINT "deliveries_id_deliveryman_fkey";

-- AlterTable
ALTER TABLE "deliveries" ALTER COLUMN "id_deliveryman" DROP NOT NULL,
ALTER COLUMN "end_at" DROP NOT NULL;

-- AddForeignKey
ALTER TABLE "deliveries" ADD CONSTRAINT "deliveries_id_deliveryman_fkey" FOREIGN KEY ("id_deliveryman") REFERENCES "deliveryman"("id") ON DELETE SET NULL ON UPDATE CASCADE;

```

--------------------------------------------------------------------------------
/src/modules/deliveries/updateEndDate/UpdateEndDateController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { UpdateEndDateUseCase } from "./UpdateEndDateUseCase";



export class UpdateEndDateController{
  async handle(request: Request, response: Response){
    const { id } = request.params;

    const updateEndDateUseCase = new UpdateEndDateUseCase()

    const result = await updateEndDateUseCase.execute({
      id_delivery: id
    })

    return response.json(result)
  }
}
```

--------------------------------------------------------------------------------
/src/modules/deliveries/useCases/updateDeliveryman/UpdateDeliverymanUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { prisma } from "../../../../database/prismaClient";

interface IUpdateDeliveryman{
  id_delivery: string;
  id_deliveryman: string;
}

export class UpdateDeliverymanUseCase{
  async execute({ id_delivery, id_deliveryman }: IUpdateDeliveryman){
    const result = await prisma.deliveries.update({
      where: {
        id: id_delivery
      },

      data: {
        id_deliveryman
      }
    })

    return result
  }
}
```

--------------------------------------------------------------------------------
/src/modules/deliveryman/useCases/findAllDeliveries/FindAllDeliveriesController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { FindAllDeliveriesUseCase } from "./FindAllDeliveriesUseCase";



export class FindAllDeliveriesController{
  async handle(request: Request, response: Response){
    const { id_deliveryman } = request

    const findAllDeliveriesUseCase = new FindAllDeliveriesUseCase()

    const result = await findAllDeliveriesUseCase.execute({
      id_deliveryman,
    })

    return response.json(result)
  }
}
```

--------------------------------------------------------------------------------
/src/modules/clients/useCases/createClient/createClientController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { CreateClientUseCase } from "./createClienteUseCase";

export class CreateClientController{
  constructor (private createClientUseCase: CreateClientUseCase){}

  async handle(request: Request, response: Response){
    const { username, password } = request.body;

    const result = await this.createClientUseCase.execute({
      username,
      password
    })

    return response.json(result)
  }
}
```

--------------------------------------------------------------------------------
/prisma/migrations/20220819213758_update_name_deliveryman/migration.sql:
--------------------------------------------------------------------------------

```sql
/*
  Warnings:

  - You are about to drop the `Deliveryman` table. If the table is not empty, all the data it contains will be lost.

*/
-- DropTable
DROP TABLE "Deliveryman";

-- CreateTable
CREATE TABLE "deliveryman" (
    "id" TEXT NOT NULL,
    "username" TEXT NOT NULL,
    "password" TEXT NOT NULL,

    CONSTRAINT "deliveryman_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "deliveryman_username_key" ON "deliveryman"("username");

```

--------------------------------------------------------------------------------
/src/modules/clients/useCases/findClientDeliveries/FindClientDeliveriesUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { prisma } from "../../../../database/prismaClient";
import { IClientRepository } from "../../../../database/repositories/interfaces/IClientRepository";

interface IFindClientDeliveries{
  id_client: string;
}

export class FindClientDeliveriesUseCase{
  constructor(
    private clientRepository: IClientRepository
  ){}

  async execute({id_client}: IFindClientDeliveries){
    const client = await this.clientRepository.find({id_client})

    return client
  }
}
```

--------------------------------------------------------------------------------
/src/modules/account/authenticateClient/AuthenticateClientController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { AuthenticateClientUseCase } from "./AuthenticateClientUseCase";



export class AuthenticateClientController{
  async handle(request: Request, response: Response){
    const { username, password } = request.body;

    const authenticateClientUseCase = new AuthenticateClientUseCase()
    const result = await authenticateClientUseCase.execute({
      username,
      password
    })

    return response.json(result)
  }
}
```

--------------------------------------------------------------------------------
/src/modules/clients/useCases/findClientDeliveries/FindClientDeliveriesController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { FindClientDeliveriesUseCase } from "./FindClientDeliveriesUseCase";



export class FindClientDeliveriesController{
  constructor(
    private findClientDeliveriesUseCase: FindClientDeliveriesUseCase
  ){}

  async handle(request: Request, response: Response){
    const { id_client } = request

    const result = await this.findClientDeliveriesUseCase.execute({
      id_client
    })

    return response.json(result)
  }
}
```

--------------------------------------------------------------------------------
/src/modules/deliveries/useCases/createDelivery/CreateDeliveryController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { CreateDeliveryUseCase } from "./CreateDeliveryUseCase";

export class CreateDeliveryController{
  async handle(request: Request, response: Response){
    const { item_name } = request.body;
    const { id_client } = request 

    const createDeliveryUseCase = new CreateDeliveryUseCase()

    const delivery = await createDeliveryUseCase.execute({
      id_client,
      item_name
    })

    return response.json(delivery)
  }
}
```

--------------------------------------------------------------------------------
/src/modules/clients/useCases/createClient/index.ts:
--------------------------------------------------------------------------------

```typescript
import { ClientRepository } from "../../../../database/repositories/ClientRepository";
import { CreateClientController } from "./createClientController";
import { CreateClientUseCase } from "./createClienteUseCase";

const clientRepository = ClientRepository.getInstance()

const createClientUseCase = new CreateClientUseCase(clientRepository)

const createClientController = new CreateClientController(createClientUseCase)

export { createClientController, clientRepository, createClientUseCase }

```

--------------------------------------------------------------------------------
/src/modules/account/authenticateDeliveryman/AuthenticateDeliverymanController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { AuthenticateDeliverymanUseCase } from "./AuthenticateDeliverymanUseCase";



export class AuthenticateDeliverymanController{
  async handle(request: Request, response: Response){
    const { username, password } = request.body;

    const authenticateDeliverymanUseCase = new AuthenticateDeliverymanUseCase()
    const result = await authenticateDeliverymanUseCase.execute({
      username,
      password
    })

    return response.json(result)
  }
}
```

--------------------------------------------------------------------------------
/src/modules/deliveries/useCases/updateDeliveryman/UpdateDeliverymanController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { UpdateDeliverymanUseCase } from "./UpdateDeliverymanUseCase";

export class UpdateDeliverymanController{
  async handle(request: Request, response: Response){
    const { id } = request.params
    const { id_deliveryman } = request

    const updateDeliverymanUseCase = new UpdateDeliverymanUseCase()

    const delivery = await updateDeliverymanUseCase.execute({
      id_delivery: id,
      id_deliveryman
    })

    return response.json(delivery)
  }
}
```

--------------------------------------------------------------------------------
/src/modules/deliveryman/useCases/findAllDeliveries/FindAllDeliveriesUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { prisma } from "../../../../database/prismaClient";

interface IFindAllDeliveries{
  id_deliveryman: string;
}

export class FindAllDeliveriesUseCase{
  async execute({ id_deliveryman }: IFindAllDeliveries){
    const deliveryman = await prisma.deliveryman.findFirst({
      where: {
        id: id_deliveryman,
      },

      select: {
        id: true,
        username: true,
        Deliveries: {
          where: {
            end_at: null
          }
        }
      }
    })

    return deliveryman
  }
}
```

--------------------------------------------------------------------------------
/src/modules/clients/useCases/findClientDeliveries/index.ts:
--------------------------------------------------------------------------------

```typescript
import { ClientRepository } from "../../../../database/repositories/ClientRepository";
import { FindClientDeliveriesController } from "./FindClientDeliveriesController";
import { FindClientDeliveriesUseCase } from "./FindClientDeliveriesUseCase";

const clientRepository = ClientRepository.getInstance()
const findClientDeliveriesUseCase = new FindClientDeliveriesUseCase(clientRepository)
const findClientDeliveriesController = new FindClientDeliveriesController(findClientDeliveriesUseCase)

export { findClientDeliveriesController }
```

--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------

```typescript
import express, { NextFunction, Request, Response } from "express";
import "express-async-errors"
import { routes } from "./routes";

const app = express()

app.use(express.json())

app.use(routes);

app.use((err: Error, request: Request, response: Response, next: NextFunction) => {
  if(err instanceof Error){
    return response.status(400).json({
      message: err.message
    })
  }

  return response.status(500).json({
    status: "error",
    message: "internal server error"
  })
})

app.listen(3333, () => console.log('server is running'))

```

--------------------------------------------------------------------------------
/src/middlewares/ensureAuthClient.ts:
--------------------------------------------------------------------------------

```typescript
import { NextFunction, Request, Response } from "express";
import { verify } from "jsonwebtoken";

interface IPayload{
  sub: string;
}

export async function ensureAuthClient(request: Request, response: Response, next: NextFunction){
  const authHeader = request.headers.authorization;

  if(!authHeader){
    return response.status(401).json({
      message: "token missing"
    })
  }

  const [, token] = authHeader.split(" ");

  try{
    const { sub } = verify(token, 'a905d89574379cec8ba1fc0438bf9597') as IPayload;
    
    request.id_client = sub;

    return next()
  }catch{
    return response.status(401).json({
      message: "Invalid token"
    })
  }
  
}
```

--------------------------------------------------------------------------------
/src/middlewares/ensureAuthDeliveryman.ts:
--------------------------------------------------------------------------------

```typescript
import { NextFunction, Request, Response } from "express";
import { verify } from "jsonwebtoken";

interface IPayload{
  sub: string;
}

export async function ensureAuthDeliveryman(request: Request, response: Response, next: NextFunction){
  const authHeader = request.headers.authorization;

  if(!authHeader){
    return response.status(401).json({
      message: "token missing"
    })
  }

  const [, token] = authHeader.split(" ");

  try{
    const { sub } = verify(token, 'a905d89574379cec8ba1fc0438bf9597') as IPayload;
    
    request.id_deliveryman = sub;

    return next()
  }catch{
    return response.status(401).json({
      message: "Invalid token"
    })
  }
  
}
```

--------------------------------------------------------------------------------
/prisma/migrations/20220819214400_create_deliveries_table/migration.sql:
--------------------------------------------------------------------------------

```sql
-- CreateTable
CREATE TABLE "deliveries" (
    "id" TEXT NOT NULL,
    "id_client" TEXT NOT NULL,
    "id_deliveryman" TEXT NOT NULL,
    "item_name" TEXT NOT NULL,
    "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "end_at" TIMESTAMP(3) NOT NULL,

    CONSTRAINT "deliveries_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "deliveries" ADD CONSTRAINT "deliveries_id_client_fkey" FOREIGN KEY ("id_client") REFERENCES "clients"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "deliveries" ADD CONSTRAINT "deliveries_id_deliveryman_fkey" FOREIGN KEY ("id_deliveryman") REFERENCES "deliveryman"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

```

--------------------------------------------------------------------------------
/src/modules/deliveryman/useCases/createDeliveryman/CreateDeliverymanController.ts:
--------------------------------------------------------------------------------

```typescript
import { Request, Response } from "express";
import { producer } from "../../../../kafka/producer";
import { CreateDeliverymanUseCase } from "./CreateDeliverymanUseCase";
import { randomUUID } from 'node:crypto'


export class CreateDeliverymanController {
  async handle(request: Request, response: Response){
    const { username, password } = request.body;

    const createDeliverymanUseCase = new CreateDeliverymanUseCase()
    const result = await createDeliverymanUseCase.execute({
      username,
      password
    })

    await producer({
      category: 'deliveryman',
      content: `Novo deliveryman criado: ${username}`,
      recipientId: randomUUID()
    })

    return response.json(result)
  }
}
```

--------------------------------------------------------------------------------
/src/modules/clients/useCases/createClient/createClienteUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { prisma } from "../../../../database/prismaClient";
import { IClientRepository } from "../../../../database/repositories/interfaces/IClientRepository";

interface ICreateClient{
  username: string;
  password: string;
}

export class CreateClientUseCase{
  constructor(private clientRepository: IClientRepository){}
  async execute({ username, password }: ICreateClient){
    const clientAlreadyExists = await prisma.clients.findFirst({
      where: {
        username: {
          equals: username,
          mode: "insensitive"
        }
      }
    })

    if(clientAlreadyExists){
      throw new Error("Client already exists")
    }

    const client = this.clientRepository.create({password, username})

    return client
  }
}
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "backend-entregas",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "type": "commonjs",
  "scripts": {
    "dev": "ts-node-dev --exit-child --transpile-only --ignore-watch node_modules src/server.ts",
    "test": "jest"
  },
  "devDependencies": {
    "@types/bcrypt": "^5.0.0",
    "@types/express": "^4.17.13",
    "@types/jest": "^29.4.0",
    "@types/jsonwebtoken": "^8.5.8",
    "jest": "^29.4.1",
    "prisma": "^4.2.1",
    "ts-jest": "^29.0.5",
    "ts-node-dev": "^2.0.0",
    "typescript": "^4.7.4"
  },
  "dependencies": {
    "@prisma/client": "^4.2.1",
    "bcrypt": "^5.0.1",
    "express": "^4.18.1",
    "express-async-errors": "^3.1.1",
    "jsonwebtoken": "^8.5.1",
    "kafkajs": "^2.2.3"
  }
}

```

--------------------------------------------------------------------------------
/src/modules/clients/useCases/findClientDeliveries/FindClientDeliveries.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { InMemoryClientRepository } from "../../../../tests/inMemoryDatabases/InMemoryClientsRepository"
import { FindClientDeliveriesUseCase } from "./FindClientDeliveriesUseCase"

const clientRepository = new InMemoryClientRepository()
const findClientDeliveries = new FindClientDeliveriesUseCase(clientRepository)

describe("Find client Delivires", () => {
  it("should found a client delivery", async() => {
    const client = await findClientDeliveries.execute({
      id_client: '455667'
    })

    expect(client).toHaveLength(1)
  })

  it("should return an error if client not found", async() => {
    expect(async () => {
      await findClientDeliveries.execute({
        id_client: '645456654'
      })
    }).rejects.toThrow()
  })
})
```

--------------------------------------------------------------------------------
/src/modules/account/authenticateClient/AuthenticateClientUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { prisma } from "../../../database/prismaClient";
import { compare } from "bcrypt"
import { sign } from "jsonwebtoken"

interface IAuthenticateClient {
  username: string;
  password: string
}

export class AuthenticateClientUseCase{
  async execute({ username, password }: IAuthenticateClient){
    const client = await prisma.clients.findFirst({
      where: {
        username
      }
    })

    if(!client){
      throw new Error("Username or password is invalid!")
    }

    const passwordMatch = await compare(password, client.password)

    if(!passwordMatch){
      throw new Error("Username or password is invalid!")
    }

    const token = sign( {username}, "a905d89574379cec8ba1fc0438bf9597", {
      subject: client.id,
      expiresIn: "1d"
    })

    return token
  }
}
```

--------------------------------------------------------------------------------
/src/modules/deliveryman/useCases/createDeliveryman/CreateDeliverymanUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { hash } from "bcrypt";
import { prisma } from "../../../../database/prismaClient";

interface ICreateDeliveryman{
  username: string;
  password: string;
}

export class CreateDeliverymanUseCase{
  async execute({ username, password }: ICreateDeliveryman){
    // validar se username já existe
    const deliverymanAlreadyExists = await prisma.deliveryman.findFirst({
      where: {
        username: {
          equals: username,
          mode: "insensitive"
        }
      }
    })

    if(deliverymanAlreadyExists){
      throw new Error("Deliveryman already exists!")
    }

    const hashPassword = await hash(password, 10);

    const deliveryman = await prisma.deliveryman.create({
      data: {
        username,
        password: hashPassword
      }
    })

    return deliveryman

  }
}
```

--------------------------------------------------------------------------------
/src/modules/account/authenticateDeliveryman/AuthenticateDeliverymanUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { prisma } from "../../../database/prismaClient";
import { compare } from "bcrypt"
import { sign } from "jsonwebtoken"

interface IAuthenticateDeliveryman {
  username: string;
  password: string
}

export class AuthenticateDeliverymanUseCase{
  async execute({ username, password }: IAuthenticateDeliveryman){
    const deliveryman = await prisma.deliveryman.findFirst({
      where: {
        username
      }
    })

    if(!deliveryman){
      throw new Error("Username or password is invalid!")
    }

    const passwordMatch = await compare(password, deliveryman.password)

    if(!passwordMatch){
      throw new Error("Username or password is invalid!")
    }

    const token = sign( {username}, "a905d89574379cec8ba1fc0438bf9597", {
      subject: deliveryman.id,
      expiresIn: "1d"
    })

    return token
  }
}
```

--------------------------------------------------------------------------------
/src/kafka/producer.ts:
--------------------------------------------------------------------------------

```typescript
import {Kafka} from 'kafkajs'

interface MessagesProps{
  content: string;
  category: string;
  recipientId: string;
}

export async function producer({category, content, recipientId}: MessagesProps){
  const kafka = new Kafka({
    clientId: 'entregas-node',
    brokers: ['stable-spider-6900-us1-kafka.upstash.io:9092'],
    sasl: {
      mechanism: 'scram-sha-256',
      username: 'c3RhYmxlLXNwaWRlci02OTAwJJw1OKOjqd2WIqt7-XXtHqrcZPbhL1aLjGLyXXM',
      password: 'b55b6a4a24404e199df02c2f6bc5b806',
    },
    ssl: true,
  })

  const producer = kafka.producer()

  await producer.connect()
  await producer.send({
    topic: 'notifications.send-notification',
    messages: [
      {
        value: JSON.stringify({
          content,
          category,
          recipientId
        })
      }
    ]
  })

  await producer.disconnect()
}
```

--------------------------------------------------------------------------------
/src/modules/clients/useCases/createClient/createClient.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { InMemoryClientRepository } from "../../../../tests/inMemoryDatabases/InMemoryClientsRepository"
import { CreateClientUseCase } from "./createClienteUseCase"

const clientRepository = new InMemoryClientRepository()
const createClientUseCase = new CreateClientUseCase(clientRepository)

describe('create client tests', () => {
  it('should create a client', async () => {
    const client = await createClientUseCase.execute({
      password: String(Math.random()),
      username: "Jhon Doe " + `${String(Math.random())}`,
    })

    expect(client).toHaveProperty('id')
  })

  it('should return an error if username already exists', async () => {
    expect(async () => {
      await createClientUseCase.execute({
        password: String(Math.random()),
        username: "jhon doe"
      })

      await createClientUseCase.execute({
        password: String(Math.random()),
        username: "jhon doe"
      })
    }).rejects.toThrow("Client already exists");
  })
})
```

--------------------------------------------------------------------------------
/src/tests/inMemoryDatabases/InMemoryClientsRepository.ts:
--------------------------------------------------------------------------------

```typescript
import { Clients } from "@prisma/client";
import { CreateRequestProps, FindRequestProps, IClientRepository } from "../../database/repositories/interfaces/IClientRepository";
import { randomUUID } from 'node:crypto'

export class InMemoryClientRepository implements IClientRepository{
  clients: Clients[]

  constructor(){
    this.clients = [{
      username: 'Jhon Doe',
      password: '123',
      id: '455667'
    }]
  }

  async create({ username, password }: CreateRequestProps): Promise<Clients> {
    const clientAlreadyExists = this.clients.find((client) => client.username === username)

    if(clientAlreadyExists){
      throw new Error("Client already exists")
    }

    const client = Object.assign({
      username,
      password,
      id: randomUUID()
    })

    this.clients.push(client)

    return client
  }
  async find({ id_client }: FindRequestProps): Promise<Clients[]> {
    const clientFound = this.clients.filter((client) => client.id === id_client)

    if(!clientFound[0]){
      throw new Error("Client with this id not found")
    }

    return clientFound
  }
}
```

--------------------------------------------------------------------------------
/src/database/repositories/ClientRepository.ts:
--------------------------------------------------------------------------------

```typescript
import { Clients } from "@prisma/client";
import { hash } from "bcrypt";
import { prisma } from "../prismaClient";
import { CreateRequestProps, FindRequestProps, IClientRepository } from "./interfaces/IClientRepository";

export class ClientRepository implements IClientRepository {
  private static INSTANCE: ClientRepository;

  public static getInstance(): ClientRepository{

    if(!ClientRepository.INSTANCE){
      ClientRepository.INSTANCE = new ClientRepository()
    }

    return ClientRepository.INSTANCE
  }

  async create({ username, password }: CreateRequestProps): Promise<Clients> {
    const hashPassword = await hash(password, 10);

    const client = await prisma.clients.create({
      data: {
        password: hashPassword,
        username,
      }
    })

    return client
  }
  async find({ id_client }: FindRequestProps): Promise<Clients[]> {
    const client = await prisma.clients.findMany({
      where: {
        id: id_client
      },
      select: {
        id: true,
        username: true,
        Deliveries: true,
        password: true
      }
    })

    return client
  }

}
```

--------------------------------------------------------------------------------
/src/routes.ts:
--------------------------------------------------------------------------------

```typescript
import { Router } from "express";
import { AuthenticateClientController } from "./modules/account/authenticateClient/AuthenticateClientController";
import { AuthenticateDeliverymanController } from "./modules/account/authenticateDeliveryman/AuthenticateDeliverymanController";
import { CreateDeliveryController } from "./modules/deliveries/useCases/createDelivery/CreateDeliveryController";
import { CreateDeliverymanController } from "./modules/deliveryman/useCases/createDeliveryman/CreateDeliverymanController";

import { ensureAuthClient } from "./middlewares/ensureAuthClient";
import { ensureAuthDeliveryman } from "./middlewares/ensureAuthDeliveryman";
import { FindAllAvailableController } from "./modules/deliveries/useCases/findAllAvailable/FindAllAvailableController";
import { UpdateDeliverymanController } from "./modules/deliveries/useCases/updateDeliveryman/UpdateDeliverymanController";
import { FindAllDeliveriesController } from "./modules/deliveryman/useCases/findAllDeliveries/FindAllDeliveriesController";
import { UpdateEndDateController } from "./modules/deliveries/updateEndDate/UpdateEndDateController";
import { createClientController } from "./modules/clients/useCases/createClient";
import { findClientDeliveriesController } from "./modules/clients/useCases/findClientDeliveries";

const routes = Router()

const authenticateClientController = new AuthenticateClientController()

const createDeliverymanController = new CreateDeliverymanController()
const authenticateDeliverymanController = new AuthenticateDeliverymanController()
const findAllAvailableController = new FindAllAvailableController()

const createDeliveryController = new CreateDeliveryController()
const updateDeliverymanController = new UpdateDeliverymanController()
const findAllDeliveriesController = new FindAllDeliveriesController()
const updateEndDateController = new UpdateEndDateController()

const authenticateClient = new AuthenticateClientController()


routes.post("/client", (req, res) => {
  return createClientController.handle(req, res)
})
routes.get("/client/myDeliveries", ensureAuthClient, (req, res) => {
  return findClientDeliveriesController.handle(req, res)
})
routes.post("/client/authenticate", authenticateClientController.handle)

routes.post("/deliveryman", createDeliverymanController.handle)
routes.get("/deliveryman/myDeliveries", ensureAuthDeliveryman, findAllDeliveriesController.handle)
routes.post("/deliveryman/authenticate", authenticateDeliverymanController.handle)
routes.put("/deliveryman/authenticate", authenticateDeliverymanController.handle)

routes.get("/delivery/available", ensureAuthDeliveryman, findAllAvailableController.handle)
routes.post("/delivery", ensureAuthClient, createDeliveryController.handle)
routes.put("/delivery/updateDeliveryman/:id", ensureAuthDeliveryman, updateDeliverymanController.handle)
routes.put("/delivery/updateEndDate/:id", ensureAuthDeliveryman, updateEndDateController.handle)

routes.post('/auth/user', authenticateClient.handle)

export { routes }
```

--------------------------------------------------------------------------------
/jest.config.ts:
--------------------------------------------------------------------------------

```typescript
/*
 * For a detailed explanation regarding each configuration property and type check, visit:
 * https://jestjs.io/docs/configuration
 */

export default {
  // All imported modules in your tests should be mocked automatically
  // automock: false,

  // Stop running tests after `n` failures
  // bail: 0,

  // The directory where Jest should store its cached dependency information
  // cacheDirectory: "C:\\Users\\rafae\\AppData\\Local\\Temp\\jest",

  // Automatically clear mock calls, instances, contexts and results before every test
  clearMocks: true,

  // Indicates whether the coverage information should be collected while executing the test
  // collectCoverage: false,

  // An array of glob patterns indicating a set of files for which coverage information should be collected
  // collectCoverageFrom: undefined,

  // The directory where Jest should output its coverage files
  // coverageDirectory: undefined,

  // An array of regexp pattern strings used to skip coverage collection
  // coveragePathIgnorePatterns: [
  //   "\\\\node_modules\\\\"
  // ],

  // Indicates which provider should be used to instrument code for coverage
  coverageProvider: "v8",

  // A list of reporter names that Jest uses when writing coverage reports
  // coverageReporters: [
  //   "json",
  //   "text",
  //   "lcov",
  //   "clover"
  // ],

  // An object that configures minimum threshold enforcement for coverage results
  // coverageThreshold: undefined,

  // A path to a custom dependency extractor
  // dependencyExtractor: undefined,

  // Make calling deprecated APIs throw helpful error messages
  // errorOnDeprecated: false,

  // The default configuration for fake timers
  // fakeTimers: {
  //   "enableGlobally": false
  // },

  // Force coverage collection from ignored files using an array of glob patterns
  // forceCoverageMatch: [],

  // A path to a module which exports an async function that is triggered once before all test suites
  // globalSetup: undefined,

  // A path to a module which exports an async function that is triggered once after all test suites
  // globalTeardown: undefined,

  // A set of global variables that need to be available in all test environments
  // globals: {},

  // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
  // maxWorkers: "50%",

  // An array of directory names to be searched recursively up from the requiring module's location
  // moduleDirectories: [
  //   "node_modules"
  // ],

  // An array of file extensions your modules use
  // moduleFileExtensions: [
  //   "js",
  //   "mjs",
  //   "cjs",
  //   "jsx",
  //   "ts",
  //   "tsx",
  //   "json",
  //   "node"
  // ],

  // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
  // moduleNameMapper: {},

  // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
  // modulePathIgnorePatterns: [],

  // Activates notifications for test results
  // notify: false,

  // An enum that specifies notification mode. Requires { notify: true }
  // notifyMode: "failure-change",

  // A preset that is used as a base for Jest's configuration
  preset: 'ts-jest',

  // Run tests from one or more projects
  // projects: undefined,

  // Use this configuration option to add custom reporters to Jest
  // reporters: undefined,

  // Automatically reset mock state before every test
  // resetMocks: false,

  // Reset the module registry before running each individual test
  // resetModules: false,

  // A path to a custom resolver
  // resolver: undefined,

  // Automatically restore mock state and implementation before every test
  // restoreMocks: false,

  // The root directory that Jest should scan for tests and modules within
  // rootDir: undefined,

  // A list of paths to directories that Jest should use to search for files in
  // roots: [
  //   "<rootDir>"
  // ],

  // Allows you to use a custom runner instead of Jest's default test runner
  // runner: "jest-runner",

  // The paths to modules that run some code to configure or set up the testing environment before each test
  // setupFiles: [],

  // A list of paths to modules that run some code to configure or set up the testing framework before each test
  // setupFilesAfterEnv: [],

  // The number of seconds after which a test is considered as slow and reported as such in the results.
  // slowTestThreshold: 5,

  // A list of paths to snapshot serializer modules Jest should use for snapshot testing
  // snapshotSerializers: [],

  // The test environment that will be used for testing
  // testEnvironment: "jest-environment-node",

  // Options that will be passed to the testEnvironment
  // testEnvironmentOptions: {},

  // Adds a location field to test results
  // testLocationInResults: false,

  // The glob patterns Jest uses to detect test files
  testMatch: [
    "**/**/*.spec.ts"
  ],

  // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
  // testPathIgnorePatterns: [
  //   "\\\\node_modules\\\\"
  // ],

  // The regexp pattern or array of patterns that Jest uses to detect test files
  // testRegex: [],

  // This option allows the use of a custom results processor
  // testResultsProcessor: undefined,

  // This option allows use of a custom test runner
  // testRunner: "jest-circus/runner",

  // A map from regular expressions to paths to transformers
  // transform: undefined,

  // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
  // transformIgnorePatterns: [
  //   "\\\\node_modules\\\\",
  //   "\\.pnp\\.[^\\\\]+$"
  // ],

  // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
  // unmockedModulePathPatterns: undefined,

  // Indicates whether each individual test should be reported during the run
  // verbose: undefined,

  // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
  // watchPathIgnorePatterns: [],

  // Whether to use watchman for file crawling
  // watchman: true,
};

```