diff --git a/src/task/task.controller.ts b/src/task/task.controller.ts index 7fe4253..56e1c4c 100644 --- a/src/task/task.controller.ts +++ b/src/task/task.controller.ts @@ -5,6 +5,7 @@ import { deleteTask, getTask, listTasks, + searchTasks, updateTask, } from "./task.service"; import { PageQueryParams } from "../pagination"; @@ -82,3 +83,17 @@ export async function deleteTaskHandler( return err; } } + +export async function searchTaskHandler( + req: FastifyRequest, + res: FastifyReply +) { + const queryParams = req.query as PageQueryParams; + + try { + const taskList = await searchTasks(queryParams, req.user.tenantId); + return res.code(200).send(taskList); + } catch (err) { + return err; + } +} diff --git a/src/task/task.route.ts b/src/task/task.route.ts index d356005..aec6674 100644 --- a/src/task/task.route.ts +++ b/src/task/task.route.ts @@ -5,6 +5,7 @@ import { deleteTaskHandler, getTaskHandler, listTaskHandler, + searchTaskHandler, updateTaskHandler, } from "./task.controller"; import { noteRoutes } from "../note/note.route"; @@ -81,6 +82,18 @@ export async function taskRoutes(fastify: FastifyInstance) { deleteTaskHandler ); + fastify.get( + "/search", + { + schema: { + querystring: $task("pageQueryParams"), + }, + config: { requiredClaims: ["task:read"] }, + preHandler: [fastify.authorize], + }, + searchTaskHandler + ); + await noteRoutes(fastify, { read: "task:read", write: "task:write", diff --git a/src/task/task.service.ts b/src/task/task.service.ts index be1cf86..fb74e02 100644 --- a/src/task/task.service.ts +++ b/src/task/task.service.ts @@ -140,3 +140,90 @@ export async function listTasks(params: PageQueryParams, tenantId: string) { export async function deleteTask(taskId: string, tenantId: string) { return await taskModel.deleteOne({ pid: taskId, tenantId: tenantId }); } + +export async function searchTasks(params: PageQueryParams, tenantId: string) { + const page = params.page || 1; + const pageSize = params.pageSize || 10; + const sortObj = getSortObject(params, taskFields); + const filterObj = getFilterObject(params, taskFields); + + const regex = new RegExp(params.searchToken, "i"); + + const taskList = await taskModel.aggregate([ + { + $match: { $and: [{ tenantId: tenantId }, ...filterObj] }, + }, + { + $match: { + $or: [{ title: { $regex: regex } }], + }, + }, + { + $lookup: { + from: "users", + localField: "createdBy", + foreignField: "_id", + as: "createdBy", + }, + }, + { + $lookup: { + from: "users", + localField: "assignedTo", + foreignField: "_id", + as: "assignedTo", + }, + }, + { + $project: { + _id: 1, + pid: 1, + title: 1, + dueDate: 1, + createdAt: 1, + createdBy: { + $let: { + vars: { createdBy: { $arrayElemAt: ["$createdBy", 0] } }, + in: { + _id: "$$createdBy._id", + pid: "$$createdBy.pid", + name: "$$createdBy.name", + }, + }, + }, + assignedTo: { + $let: { + vars: { assignedTo: { $arrayElemAt: ["$assignedTo", 0] } }, + in: { + _id: "$$assignedTo._id", + pid: "$$assignedTo.pid", + name: "$$assignedTo.name", + }, + }, + }, + }, + }, + { + $facet: { + metadata: [{ $count: "count" }], + data: [ + { $skip: (page - 1) * pageSize }, + { $limit: pageSize }, + { $sort: sortObj }, + ], + }, + }, + ]); + + if (taskList[0].data.length === 0) + return { tasks: [], metadata: { count: 0, page, pageSize } }; + + return { + tasks: taskList[0]?.data, + metadata: { + count: taskList[0].metadata[0].count, + page, + pageSize, + }, + }; +}