From 948eefa302c65511efc1b6c9b69f62258bb0a5e2 Mon Sep 17 00:00:00 2001 From: potts99 Date: Sun, 26 Nov 2023 23:55:14 +0000 Subject: [PATCH] checks --- apps/api/src/controllers/auth.ts | 36 ++--- apps/api/src/controllers/clients.ts | 103 +++++++------ apps/api/src/controllers/data.ts | 50 +++++-- apps/api/src/controllers/notebook.ts | 70 ++++++--- apps/api/src/controllers/queue.ts | 81 ++++++----- apps/api/src/controllers/ticket.ts | 210 ++++++++++++++------------- apps/api/src/controllers/todos.ts | 76 ++++++---- apps/api/src/controllers/webhooks.ts | 60 +++++--- apps/api/src/lib/checks.ts | 20 ++- 9 files changed, 425 insertions(+), 281 deletions(-) diff --git a/apps/api/src/controllers/auth.ts b/apps/api/src/controllers/auth.ts index 7faeb4bec..20e62c5af 100644 --- a/apps/api/src/controllers/auth.ts +++ b/apps/api/src/controllers/auth.ts @@ -141,13 +141,18 @@ export function authRoutes(fastify: FastifyInstance) { fastify.delete( "/api/v1/auth/user/:id", async (request: FastifyRequest, reply: FastifyReply) => { - const { id } = request.params as { id: string }; + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); - await prisma.user.delete({ - where: { id }, - }); + if (token) { + const { id } = request.params as { id: string }; - reply.send({ success: true }); + await prisma.user.delete({ + where: { id }, + }); + + reply.send({ success: true }); + } } ); @@ -155,11 +160,6 @@ export function authRoutes(fastify: FastifyInstance) { fastify.get( "/api/v1/auth/profile", async (request: FastifyRequest, reply: FastifyReply) => { - // check token - // see if token exists on session table - // if not, return 401 - // if yes, return user data - const bearer = request.headers.authorization!.split(" ")[1]; const token = checkToken(bearer); @@ -211,8 +211,6 @@ export function authRoutes(fastify: FastifyInstance) { }; const bearer = request.headers.authorization!.split(" ")[1]; - - //checks if token is valid and returns valid token const token = checkToken(bearer); if (token) { @@ -288,13 +286,17 @@ export function authRoutes(fastify: FastifyInstance) { fastify.get( "/api/v1/auth/user/:id/logout", async (request: FastifyRequest, reply: FastifyReply) => { - const { id } = request.params as { id: string }; + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + if (token) { + const { id } = request.params as { id: string }; - await prisma.session.deleteMany({ - where: { userId: id }, - }); + await prisma.session.deleteMany({ + where: { userId: id }, + }); - reply.send({ success: true }); + reply.send({ success: true }); + } } ); } diff --git a/apps/api/src/controllers/clients.ts b/apps/api/src/controllers/clients.ts index fa1868491..c3a9b63a5 100644 --- a/apps/api/src/controllers/clients.ts +++ b/apps/api/src/controllers/clients.ts @@ -1,4 +1,5 @@ import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; +import { checkToken } from "../lib/jwt"; import { prisma } from "../prisma"; export function clientRoutes(fastify: FastifyInstance) { @@ -7,20 +8,25 @@ export function clientRoutes(fastify: FastifyInstance) { "/api/v1/client/create", async (request: FastifyRequest, reply: FastifyReply) => { - const { name, email, number, contactName }: any = request.body; - - await prisma.client.create({ - data: { - name, - contactName, - email, - number: String(number), - }, - }); - - reply.send({ - success: true, - }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const { name, email, number, contactName }: any = request.body; + + await prisma.client.create({ + data: { + name, + contactName, + email, + number: String(number), + }, + }); + + reply.send({ + success: true, + }); + } } ); @@ -29,21 +35,26 @@ export function clientRoutes(fastify: FastifyInstance) { "/api/v1/client/update", async (request: FastifyRequest, reply: FastifyReply) => { - const { name, email, number, contactName, id }: any = request.body; - - await prisma.client.update({ - where: { id: id }, - data: { - name, - contactName, - email, - number: String(number), - }, - }); - - reply.send({ - success: true, - }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const { name, email, number, contactName, id }: any = request.body; + + await prisma.client.update({ + where: { id: id }, + data: { + name, + contactName, + email, + number: String(number), + }, + }); + + reply.send({ + success: true, + }); + } } ); @@ -52,12 +63,17 @@ export function clientRoutes(fastify: FastifyInstance) { "/api/v1/clients/all", async (request: FastifyRequest, reply: FastifyReply) => { - const clients = await prisma.client.findMany({}); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); - reply.send({ - success: true, - clients: clients, - }); + if (token) { + const clients = await prisma.client.findMany({}); + + reply.send({ + success: true, + clients: clients, + }); + } } ); @@ -66,15 +82,20 @@ export function clientRoutes(fastify: FastifyInstance) { "/api/v1/clients/:id/delete-client", async (request: FastifyRequest, reply: FastifyReply) => { - const { id }: any = request.params; + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const { id }: any = request.params; - await prisma.client.delete({ - where: { id: id }, - }); + await prisma.client.delete({ + where: { id: id }, + }); - reply.send({ - success: true, - }); + reply.send({ + success: true, + }); + } } ); } diff --git a/apps/api/src/controllers/data.ts b/apps/api/src/controllers/data.ts index a8d3ba361..e3c6e69b2 100644 --- a/apps/api/src/controllers/data.ts +++ b/apps/api/src/controllers/data.ts @@ -1,4 +1,5 @@ import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; +import { checkToken } from "../lib/jwt"; import { prisma } from "../prisma"; export function dataRoutes(fastify: FastifyInstance) { @@ -7,8 +8,14 @@ export function dataRoutes(fastify: FastifyInstance) { "/api/v1/data/tickets/all", async (request: FastifyRequest, reply: FastifyReply) => { - // check jwt is valid - // check user is admin + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const result = await prisma.ticket.count(); + + reply.send({ count: result }); + } } ); @@ -17,11 +24,16 @@ export function dataRoutes(fastify: FastifyInstance) { "/api/v1/data/tickets/completed", async (request: FastifyRequest, reply: FastifyReply) => { - const result = await prisma.ticket.count({ - where: { isComplete: true }, - }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const result = await prisma.ticket.count({ + where: { isComplete: true }, + }); - reply.send({ count: result }); + reply.send({ count: result }); + } } ); @@ -30,11 +42,16 @@ export function dataRoutes(fastify: FastifyInstance) { "/api/v1/data/tickets/open", async (request: FastifyRequest, reply: FastifyReply) => { - const result = await prisma.ticket.count({ - where: { isComplete: false }, - }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); - reply.send({ count: result }); + if (token) { + const result = await prisma.ticket.count({ + where: { isComplete: false }, + }); + + reply.send({ count: result }); + } } ); @@ -43,11 +60,16 @@ export function dataRoutes(fastify: FastifyInstance) { "/api/v1/data/tickets/unassigned", async (request: FastifyRequest, reply: FastifyReply) => { - const result = await prisma.ticket.count({ - where: { userId: null }, - }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const result = await prisma.ticket.count({ + where: { userId: null }, + }); - reply.send({ count: result }); + reply.send({ count: result }); + } } ); } diff --git a/apps/api/src/controllers/notebook.ts b/apps/api/src/controllers/notebook.ts index 13f601ab9..0452452a4 100644 --- a/apps/api/src/controllers/notebook.ts +++ b/apps/api/src/controllers/notebook.ts @@ -17,19 +17,21 @@ export function notebookRoutes(fastify: FastifyInstance) { if (!title) { return reply.status(422).send({ error: "Please add a title" }); } else { - const user = await checkSession(bearer); + if (token) { + const user = await checkSession(bearer); - const data = await prisma.notes.create({ - data: { - title, - note: content, - userId: user!.id, - }, - }); + const data = await prisma.notes.create({ + data: { + title, + note: content, + userId: user!.id, + }, + }); - const { id } = data; + const { id } = data; - reply.status(200).send({ success: true, id }); + reply.status(200).send({ success: true, id }); + } } } ); @@ -41,13 +43,16 @@ export function notebookRoutes(fastify: FastifyInstance) { async (request: FastifyRequest, reply: FastifyReply) => { const bearer = request.headers.authorization!.split(" ")[1]; const token = checkToken(bearer); - const user = await checkSession(bearer); - const notebooks = await prisma.notes.findMany({ - where: { userId: user!.id }, - }); + if (token) { + const user = await checkSession(bearer); + + const notebooks = await prisma.notes.findMany({ + where: { userId: user!.id }, + }); - reply.status(200).send({ success: true, notebooks: notebooks }); + reply.status(200).send({ success: true, notebooks: notebooks }); + } } ); @@ -58,19 +63,40 @@ export function notebookRoutes(fastify: FastifyInstance) { async (request: FastifyRequest, reply: FastifyReply) => { const bearer = request.headers.authorization!.split(" ")[1]; const token = checkToken(bearer); - const user = await checkSession(bearer); - const { id }: any = request.params; + if (token) { + const user = await checkSession(bearer); + + const { id }: any = request.params; - const note = await prisma.notes.findUnique({ - where: { userId: user!.id, id: id }, - }); + const note = await prisma.notes.findUnique({ + where: { userId: user!.id, id: id }, + }); - reply.status(200).send({ success: true, note }); + reply.status(200).send({ success: true, note }); + } } ); // Delete an entry + fastify.delete( + "/api/v1/notebooks/note/:id/delete", + + async (request: FastifyRequest, reply: FastifyReply) => { + const { id }: any = request.params; + + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + await prisma.notes.delete({ + where: { id: id }, + }); + + reply.status(200).send({ success: true }); + } + } + ); // Update an entry fastify.put( @@ -84,7 +110,7 @@ export function notebookRoutes(fastify: FastifyInstance) { const token = checkToken(bearer); if (token) { - const user = await checkSession(bearer); + await checkSession(bearer); await prisma.notes.update({ where: { id: id }, diff --git a/apps/api/src/controllers/queue.ts b/apps/api/src/controllers/queue.ts index 12171df17..ae7dcdaa7 100644 --- a/apps/api/src/controllers/queue.ts +++ b/apps/api/src/controllers/queue.ts @@ -1,4 +1,5 @@ import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; +import { checkToken } from "../lib/jwt"; import { prisma } from "../prisma"; export function emailQueueRoutes(fastify: FastifyInstance) { @@ -7,21 +8,26 @@ export function emailQueueRoutes(fastify: FastifyInstance) { "/api/v1/email-queue/create", async (request: FastifyRequest, reply: FastifyReply) => { - const { name, username, password, hostname, tls }: any = request.body; - - await prisma.emailQueue.create({ - data: { - name, - username, - password, - hostname, - tls, - }, - }); - - reply.send({ - success: true, - }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const { name, username, password, hostname, tls }: any = request.body; + + await prisma.emailQueue.create({ + data: { + name, + username, + password, + hostname, + tls, + }, + }); + + reply.send({ + success: true, + }); + } } ); @@ -31,14 +37,17 @@ export function emailQueueRoutes(fastify: FastifyInstance) { "/api/v1/email-queues/all", async (request: FastifyRequest, reply: FastifyReply) => { - // check jwt is valid - // check user is admin - const queues = await prisma.emailQueue.findMany({}); - - reply.send({ - success: true, - queues: queues, - }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const queues = await prisma.emailQueue.findMany({}); + + reply.send({ + success: true, + queues: queues, + }); + } } ); @@ -47,16 +56,22 @@ export function emailQueueRoutes(fastify: FastifyInstance) { "/api/v1/email-queue/delete", async (request: FastifyRequest, reply: FastifyReply) => { - const { id }: any = request.body; - const queues = await prisma.emailQueue.delete({ - where: { - id: id, - }, - }); - - reply.send({ - success: true, - }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const { id }: any = request.params; + + await prisma.emailQueue.delete({ + where: { + id: id, + }, + }); + + reply.send({ + success: true, + }); + } } ); } diff --git a/apps/api/src/controllers/ticket.ts b/apps/api/src/controllers/ticket.ts index f1aeff869..febb19d03 100644 --- a/apps/api/src/controllers/ticket.ts +++ b/apps/api/src/controllers/ticket.ts @@ -22,8 +22,6 @@ export function ticketRoutes(fastify: FastifyInstance) { type, }: any = request.body; - console.log(request.body); - const ticket: any = await prisma.ticket.create({ data: { name, @@ -146,7 +144,6 @@ export function ticketRoutes(fastify: FastifyInstance) { // Get all tickets fastify.get( "/api/v1/tickets/open", - async (request: FastifyRequest, reply: FastifyReply) => { const bearer = request.headers.authorization!.split(" ")[1]; const token = checkToken(bearer); @@ -300,68 +297,73 @@ export function ticketRoutes(fastify: FastifyInstance) { "/api/v1/ticket/transfer", async (request: FastifyRequest, reply: FastifyReply) => { + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + const { user, id }: any = request.body; - await prisma.user.update({ - where: { id: user }, - data: { - tickets: { - connect: { - id: id, + if (token) { + await prisma.user.update({ + where: { id: user }, + data: { + tickets: { + connect: { + id: id, + }, }, }, - }, - }); + }); - reply.send({ - success: true, - }); + reply.send({ + success: true, + }); + } } ); // Link a ticket to another ticket - fastify.post( - "/api/v1/ticket/link", - - async (request: FastifyRequest, reply: FastifyReply) => { - const { ticket, id }: any = request.body; - - const prev: any = await prisma.ticket.findUnique({ - where: { - id: id, - }, - }); - - const ids = []; - - if (prev.length !== undefined && prev.linked.length > 0) { - ids.push(...prev.linked); - } - - ids.push({ - id: ticket.id, - title: ticket.title, - }); - - const data = await prisma.ticket.update({ - where: { - id: id, - }, - data: { - linked: { - ...ids, - }, - }, - }); - } - ); + // fastify.post( + // "/api/v1/ticket/link", + + // async (request: FastifyRequest, reply: FastifyReply) => { + // const { ticket, id }: any = request.body; + + // const prev: any = await prisma.ticket.findUnique({ + // where: { + // id: id, + // }, + // }); + + // const ids = []; + + // if (prev.length !== undefined && prev.linked.length > 0) { + // ids.push(...prev.linked); + // } + + // ids.push({ + // id: ticket.id, + // title: ticket.title, + // }); + + // const data = await prisma.ticket.update({ + // where: { + // id: id, + // }, + // data: { + // linked: { + // ...ids, + // }, + // }, + // }); + // } + // ); // Unlink a ticket from another ticket - fastify.post( - "/api/v1/ticket/unlink", + // fastify.post( + // "/api/v1/ticket/unlink", - async (request: FastifyRequest, reply: FastifyReply) => {} - ); + // async (request: FastifyRequest, reply: FastifyReply) => {} + // ); // Comment on a ticket fastify.post( @@ -397,44 +399,49 @@ export function ticketRoutes(fastify: FastifyInstance) { "/api/v1/ticket/status/update", async (request: FastifyRequest, reply: FastifyReply) => { - const { status, id }: any = request.body; - - const ticket: any = await prisma.ticket - .update({ - where: { id: id }, - data: { - isComplete: status, - }, - }) - .then(async (ticket) => { - // await sendTicketStatus(ticket); - }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); - const webhook = await prisma.webhooks.findMany({ - where: { - type: "ticket_status_changed", - }, - }); + if (token) { + const { status, id }: any = request.body; - for (let i = 0; i < webhook.length; i++) { - if (webhook[i].active === true) { - const s = status ? "Completed" : "Outstanding"; - await axios.post(`${webhook[i].url}`, { - method: "POST", - headers: { - "Content-Type": "application/json", + const ticket: any = await prisma.ticket + .update({ + where: { id: id }, + data: { + isComplete: status, }, - body: JSON.stringify({ - data: `Ticket ${ticket.id} created by ${ticket.email}, has had it's status changed to ${s}`, - }), - redirect: "follow", + }) + .then(async (ticket) => { + // await sendTicketStatus(ticket); }); + + const webhook = await prisma.webhooks.findMany({ + where: { + type: "ticket_status_changed", + }, + }); + + for (let i = 0; i < webhook.length; i++) { + if (webhook[i].active === true) { + const s = status ? "Completed" : "Outstanding"; + await axios.post(`${webhook[i].url}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + data: `Ticket ${ticket.id} created by ${ticket.email}, has had it's status changed to ${s}`, + }), + redirect: "follow", + }); + } } - } - reply.send({ - success: true, - }); + reply.send({ + success: true, + }); + } } ); @@ -443,22 +450,27 @@ export function ticketRoutes(fastify: FastifyInstance) { "/api/v1/ticket/status/hide", async (request: FastifyRequest, reply: FastifyReply) => { - const { hidden, id }: any = request.body; + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); - await prisma.ticket - .update({ - where: { id: id }, - data: { - hidden: hidden, - }, - }) - .then(async (ticket) => { - // await sendTicketStatus(ticket); - }); + if (token) { + const { hidden, id }: any = request.body; - reply.send({ - success: true, - }); + await prisma.ticket + .update({ + where: { id: id }, + data: { + hidden: hidden, + }, + }) + .then(async (ticket) => { + // await sendTicketStatus(ticket); + }); + + reply.send({ + success: true, + }); + } } ); diff --git a/apps/api/src/controllers/todos.ts b/apps/api/src/controllers/todos.ts index 9083679d5..10f859a9c 100644 --- a/apps/api/src/controllers/todos.ts +++ b/apps/api/src/controllers/todos.ts @@ -30,20 +30,22 @@ export function todoRoutes(fastify: FastifyInstance) { console.log("No text found!"); reply.status(400).send({ success: false, message: "No text found!" }); } else { - const user = await checkSession(bearer); - - if (user) { - await prisma.todos.create({ - data: { - text: todo, - userId: user!.id, - }, - }); - reply.send({ success: true, message: "Todo created!" }); - } else { - reply - .status(400) - .send({ success: false, message: "User not found!" }); + if (token) { + const user = await checkSession(bearer); + + if (user) { + await prisma.todos.create({ + data: { + text: todo, + userId: user!.id, + }, + }); + reply.send({ success: true, message: "Todo created!" }); + } else { + reply + .status(400) + .send({ success: false, message: "User not found!" }); + } } } } @@ -55,11 +57,16 @@ export function todoRoutes(fastify: FastifyInstance) { "/api/v1/todos/all", async (request: FastifyRequest, reply: FastifyReply) => { - const todos = await prisma.todos.findMany({}); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const todos = await prisma.todos.findMany({}); - reply.send({ - todos: todos, - }); + reply.send({ + todos: todos, + }); + } } ); @@ -68,24 +75,29 @@ export function todoRoutes(fastify: FastifyInstance) { "/api/v1/todo/:id/delete", async (request: FastifyRequest, reply: FastifyReply) => { - const { id } = request.params as { id: string }; + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); - const todo = await doesTodoExist(id); + if (token) { + const { id } = request.params as { id: string }; - if (!todo) { - return reply.status(404).send({ - success: false, - error: "Todo not found.", - }); - } + const todo = await doesTodoExist(id); + + if (!todo) { + return reply.status(404).send({ + success: false, + error: "Todo not found.", + }); + } - await prisma.todos.delete({ - where: { - id: id, - }, - }); + await prisma.todos.delete({ + where: { + id: id, + }, + }); - reply.status(201).send({ success: true, message: "Todo deleted" }); + reply.status(201).send({ success: true, message: "Todo deleted" }); + } } ); } diff --git a/apps/api/src/controllers/webhooks.ts b/apps/api/src/controllers/webhooks.ts index 5cecfecb6..0da80efc0 100644 --- a/apps/api/src/controllers/webhooks.ts +++ b/apps/api/src/controllers/webhooks.ts @@ -1,4 +1,5 @@ import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; +import { checkToken } from "../lib/jwt"; import { prisma } from "../prisma"; export function webhookRoutes(fastify: FastifyInstance) { @@ -7,18 +8,23 @@ export function webhookRoutes(fastify: FastifyInstance) { "/api/v1/webhook/create", async (request: FastifyRequest, reply: FastifyReply) => { - const { name, url, type, active, secret }: any = request.body; - await prisma.webhooks.create({ - data: { - name, - url, - type, - active, - secret, - createdBy: "375f7799-5485-40ff-ba8f-0a28e0855ecf", - }, - }); - reply.status(200).send({ message: "Hook created!", success: true }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const { name, url, type, active, secret }: any = request.body; + await prisma.webhooks.create({ + data: { + name, + url, + type, + active, + secret, + createdBy: "375f7799-5485-40ff-ba8f-0a28e0855ecf", + }, + }); + reply.status(200).send({ message: "Hook created!", success: true }); + } } ); @@ -27,9 +33,14 @@ export function webhookRoutes(fastify: FastifyInstance) { "/api/v1/webhooks/all", async (request: FastifyRequest, reply: FastifyReply) => { - const webhooks = await prisma.webhooks.findMany({}); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const webhooks = await prisma.webhooks.findMany({}); - reply.status(200).send({ webhooks: webhooks, success: true }); + reply.status(200).send({ webhooks: webhooks, success: true }); + } } ); @@ -39,14 +50,19 @@ export function webhookRoutes(fastify: FastifyInstance) { "/api/v1/admin/webhook/:id/delete", async (request: FastifyRequest, reply: FastifyReply) => { - const { id }: any = request.params; - await prisma.webhooks.delete({ - where: { - id: id, - }, - }); - - reply.status(200).send({ success: true }); + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (token) { + const { id }: any = request.params; + await prisma.webhooks.delete({ + where: { + id: id, + }, + }); + + reply.status(200).send({ success: true }); + } } ); } diff --git a/apps/api/src/lib/checks.ts b/apps/api/src/lib/checks.ts index 36e2314c9..985e707da 100644 --- a/apps/api/src/lib/checks.ts +++ b/apps/api/src/lib/checks.ts @@ -1 +1,19 @@ -// is Admin +import { FastifyReply, FastifyRequest } from "fastify"; +import { checkToken } from "./jwt"; + +// Check valid token +export const authenticateUser = ( + request: FastifyRequest, + reply: FastifyReply, + done: any +) => { + const bearer = request.headers.authorization!.split(" ")[1]; + const token = checkToken(bearer); + + if (!token) { + return reply.code(401).send({ error: "Unauthorized" }); + } + + // User is authenticated, continue to the route handler + done(); +};