diff options
| author | zwlucas <lucas.fariamo08@gmail.com> | 2026-07-25 21:23:29 +0000 |
|---|---|---|
| committer | zwlucas <lucas.fariamo08@gmail.com> | 2026-07-25 21:23:29 +0000 |
| commit | ef55d9bb24430610b60c1b77821307cd72c08c55 (patch) | |
| tree | e6935a810b34370b0a4c821e55f6397aac50c832 /api/src/modules/tickets/tickets.controller.ts | |
| download | helpdesk-master.tar.gz helpdesk-master.zip | |
Signed-off-by: zwlucas <lucas.fariamo08@gmail.com>
Diffstat (limited to 'api/src/modules/tickets/tickets.controller.ts')
| -rw-r--r-- | api/src/modules/tickets/tickets.controller.ts | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/api/src/modules/tickets/tickets.controller.ts b/api/src/modules/tickets/tickets.controller.ts new file mode 100644 index 0000000..552974a --- /dev/null +++ b/api/src/modules/tickets/tickets.controller.ts @@ -0,0 +1,112 @@ +/** + * tickets.controller.ts + * + * Lógica de negócio do módulo de tickets. + * Orquestra o repository, aplica regras e formata respostas. + * NÃO acessa o banco diretamente — delega ao repository. + */ + +import type { FastifyReply, FastifyRequest } from 'fastify'; +import { createTicket, countTickets, findManyTickets } from './tickets.repository.js'; +import type { CreateTicketBody, ListTicketsQuery, TicketParams } from './tickets.schema.js'; +import { tickets } from '@/db/schema.js'; +import { eq } from 'drizzle-orm'; + +// ─── POST /tickets ──────────────────────────────────────────────────────────── + +export async function createTicketHandler( + request: FastifyRequest<{ Body: CreateTicketBody }>, + reply: FastifyReply, +) { + const { title, description, priority, categoryId, creatorId } = request.body; + + const ticket = await createTicket(request.server.db, { + title, + description, + priority, + categoryId: categoryId ?? null, + assigneeId: null, // Chamados nascem sem agente atribuído + creatorId, + status: 'open', + dueAt: null, + resolvedAt: null, + }); + + request.server.events.emit('ticket.created', { + id: ticket.id, + title: ticket.title, + creatorId: ticket.creatorId, + }); + + return reply.code(201).send(ticket); +} + +// ─── GET /tickets ───────────────────────────────────────────────────────────── + +export async function listTicketsHandler( + request: FastifyRequest<{ Querystring: ListTicketsQuery }>, + reply: FastifyReply, +) { + const filters = request.query; + const db = request.server.db; + + // Executa contagem e listagem em paralelo para não dobrar o tempo de resposta + const [total, data] = await Promise.all([ + countTickets(db, filters), + findManyTickets(db, filters), + ]); + + const totalPages = Math.ceil(total / filters.limit); + + return reply.send({ + data, + meta: { + page: filters.page, + limit: filters.limit, + total, + totalPages, + }, + }); +} + +// ─── GET /tickets/:id ───────────────────────────────────────────────────────── + +export async function getTicketByIdHandler( + request: FastifyRequest<{ Params: TicketParams }>, + reply: FastifyReply, +) { + const { findTicketById } = await import('./tickets.repository.js'); + const ticket = await findTicketById(request.server.db, request.params.id); + + if (!ticket) { + return reply.notFound(`Ticket #${request.params.id} não encontrado`); + } + + return reply.send(ticket); +} + +// ─── DELETE /tickets/:id ────────────────────────────────────────────────────── + +export async function deleteTicketHandler( + request: FastifyRequest<{ Params: TicketParams }>, + reply: FastifyReply, +) { + const db = request.server.db; + const { id } = request.params; + const callerUser = request.user!; + + const { findTicketById } = await import('./tickets.repository.js'); + const existingTicket = await findTicketById(db, id); + + if (!existingTicket) { + return reply.notFound('Chamado não encontrado.'); + } + + if (callerUser.role !== 'admin' && existingTicket.creatorId !== callerUser.id) { + return reply.forbidden('Você não tem permissão para excluir este chamado.'); + } + + await db.delete(tickets).where(eq(tickets.id, id)); + + return reply.code(204).send(); +} |