diff --git a/src/organization/organization.controller.ts b/src/organization/organization.controller.ts index 5834203..657b505 100644 --- a/src/organization/organization.controller.ts +++ b/src/organization/organization.controller.ts @@ -4,7 +4,9 @@ import { createOrg, deleteOrg, getOrg, + getUniqueValuesOrg, listOrgs, + searchOrgs, updateOrg, } from "./organization.service"; import { PageQueryParams } from "../pagination"; @@ -77,3 +79,29 @@ export async function deleteOrgHandler(req: FastifyRequest, res: FastifyReply) { return err; } } + +export async function searchOrgHandler(req: FastifyRequest, res: FastifyReply) { + const queryParams = req.query as PageQueryParams; + + try { + const authUser = req.user; + const orgList = await searchOrgs(queryParams, authUser.tenantId); + return res.code(200).send(orgList); + } catch (err) { + return err; + } +} + +export async function getUniqueFieldValuesOrg( + req: FastifyRequest, + res: FastifyReply +) { + const { field } = req.params as { field: string }; + + try { + const uniqueValues = await getUniqueValuesOrg(field, req.user.tenantId); + return res.code(200).send(uniqueValues); + } catch (err) { + return err; + } +} diff --git a/src/organization/organization.route.ts b/src/organization/organization.route.ts index fee9f90..4b6e769 100644 --- a/src/organization/organization.route.ts +++ b/src/organization/organization.route.ts @@ -4,7 +4,9 @@ import { createOrgHandler, deleteOrgHandler, getOrgHandler, + getUniqueFieldValuesOrg, listOrgsHandler, + searchOrgHandler, updateOrgHandler, } from "./organization.controller"; import { hideFields } from "../auth"; @@ -76,5 +78,32 @@ export default function organizationRoutes(fastify: FastifyInstance) { deleteOrgHandler ); + fastify.get( + "/search", + { + schema: { + querystring: $org("pageQueryParams"), + }, + config: { requiredClaims: ["org:read"] }, + preHandler: [fastify.authorize], + }, + searchOrgHandler + ); + + fastify.get( + "/fields/:field", + { + schema: { + params: { + type: "object", + properties: { field: { type: "string" } }, + }, + }, + config: { requiredClaims: ["org:read"] }, + preHandler: [fastify.authorize], + }, + getUniqueFieldValuesOrg + ); + fastify.addHook("onSend", hideFields("orgs")); } diff --git a/src/organization/organization.service.ts b/src/organization/organization.service.ts index d51605a..38ac869 100644 --- a/src/organization/organization.service.ts +++ b/src/organization/organization.service.ts @@ -78,3 +78,50 @@ export async function deleteOrg(orgId: string, tenantId: string) { $and: [{ tenantId: tenantId }, { pid: orgId }], }); } + +export async function searchOrgs(params: PageQueryParams, tenantId: string) { + const page = params.page || 1; + const pageSize = params.pageSize || 10; + const sortObj = getSortObject(params, orgFields); + const filterObj = getFilterObject(params, orgFields); + + if (!params.searchToken) + return { orgs: [], metadata: { count: 0, page, pageSize } }; + + const regex = new RegExp(params.searchToken, "i"); + + const orgs = await orgModel.aggregate([ + { $match: { $and: [{ tenantId: tenantId }, ...filterObj] } }, + { + $match: { + $or: [{ name: { $regex: regex } }, { domain: { $regex: regex } }], + }, + }, + { + $facet: { + metadata: [{ $count: "count" }], + data: [ + { $skip: (page - 1) * pageSize }, + { $limit: pageSize }, + { $sort: sortObj }, + ], + }, + }, + ]); + + if (orgs[0].data.length === 0) + return { orgs: [], metadata: { count: 0, page, pageSize } }; + + return { + orgs: orgs[0].data, + metadata: { + count: orgs[0].metadata[0].count, + page, + pageSize, + }, + }; +} + +export async function getUniqueValuesOrg(field: string, tenenatId: string) { + return await orgModel.distinct(field, { tenantId: tenenatId }); +} diff --git a/src/pagination.ts b/src/pagination.ts index bb9165c..ae65990 100644 --- a/src/pagination.ts +++ b/src/pagination.ts @@ -12,6 +12,7 @@ export const pageQueryParams = z.object({ pageSize: z.number().optional(), sort: z.string().optional(), filter: z.string().optional(), + searchToken: z.string().optional(), }); export type PageQueryParams = z.infer; diff --git a/src/permit/permit.controller.ts b/src/permit/permit.controller.ts index 15e6620..464d6de 100644 --- a/src/permit/permit.controller.ts +++ b/src/permit/permit.controller.ts @@ -4,8 +4,9 @@ import { createPermit, deletePermit, getPermit, - getUniqueValues, + getUniqueValuesPermit, listPermits, + searchPermit, updatePermit, } from "./permit.service"; import { PageQueryParams } from "../pagination"; @@ -92,14 +93,29 @@ export async function deletePermitHandler( } } -export async function getUniqueFieldValues( +export async function searchPermitHandler( + req: FastifyRequest, + res: FastifyReply +) { + const queryParams = req.query as PageQueryParams; + + try { + const authUser = req.user; + const permitList = await searchPermit(queryParams, authUser.tenantId); + return res.code(200).send(permitList); + } catch (err) { + return err; + } +} + +export async function getUniqueFieldValuesPermit( req: FastifyRequest, res: FastifyReply ) { const { field } = req.params as { field: string }; try { - const uniqueValues = await getUniqueValues(field, req.user.tenantId); + const uniqueValues = await getUniqueValuesPermit(field, req.user.tenantId); return res.code(200).send(uniqueValues); } catch (err) { return err; diff --git a/src/permit/permit.route.ts b/src/permit/permit.route.ts index 6bc45e1..668e690 100644 --- a/src/permit/permit.route.ts +++ b/src/permit/permit.route.ts @@ -3,8 +3,9 @@ import { createPermitHandler, deletePermitHandler, getPermitHandler, - getUniqueFieldValues, + getUniqueFieldValuesPermit, listPermitsHandler, + searchPermitHandler, updatePermitHandler, } from "./permit.controller"; import { $permit } from "./permit.schema"; @@ -82,6 +83,19 @@ export async function permitRoutes(fastify: FastifyInstance) { deletePermitHandler ); + fastify.get( + "/search", + { + schema: { + querystring: $permit("pageQueryParams"), + }, + + config: { requiredClaims: ["permit:read"] }, + preHandler: [fastify.authorize], + }, + searchPermitHandler + ); + fastify.get( "/fields/:field", { @@ -94,7 +108,7 @@ export async function permitRoutes(fastify: FastifyInstance) { config: { requiredClaims: ["permit:read"] }, preHandler: [fastify.authorize], }, - getUniqueFieldValues + getUniqueFieldValuesPermit ); fastify.addHook("onSend", hideFields("permits")); diff --git a/src/permit/permit.service.ts b/src/permit/permit.service.ts index 8a29aa6..3d47a46 100644 --- a/src/permit/permit.service.ts +++ b/src/permit/permit.service.ts @@ -181,7 +181,144 @@ export async function deletePermit(permitId: string, tenantId: string) { }); } -export async function getUniqueValues(field: string, tenenatId: string) { +export async function searchPermit(params: PageQueryParams, tenantId: string) { + const page = params.page || 1; + const pageSize = params.pageSize || 10; + const sortObj = getSortObject(params, permitFields); + const filterObj = getFilterObject(params, permitFields); + + if (!params.searchToken) + return { permits: [], metadata: { count: 0, page, pageSize } }; + + const regex = new RegExp(params.searchToken, "i"); + + const permitsList = await permitModel.aggregate([ + { + $match: { $and: [{ tenantId: tenantId }, ...filterObj] }, + }, + { + $match: { + $or: [ + { permitNumber: { $regex: regex } }, + { link: { $regex: regex } }, + { address: { $regex: regex } }, + ], + }, + }, + { + $lookup: { + from: "organizations", + localField: "county", + foreignField: "_id", + as: "countyRec", + }, + }, + { + $lookup: { + from: "organizations", + localField: "client", + foreignField: "_id", + as: "clientRec", + }, + }, + { + $lookup: { + from: "users", + localField: "assignedTo", + foreignField: "_id", + as: "assignedRec", + }, + }, + { + $lookup: { + from: "users", + localField: "createdBy", + foreignField: "_id", + as: "createdRec", + }, + }, + { + $project: { + _id: 1, + pid: 1, + permitNumber: 1, + permitDate: 1, + stage: 1, + status: 1, + county: { + $let: { + vars: { county: { $arrayElemAt: ["$countyRec", 0] } }, + in: { + _id: "$$county._id", + pid: "$$county.pid", + name: "$$county.name", + type: "$$county.type", + avatar: "$$county.avatar", + }, + }, + }, + client: { + $let: { + vars: { client: { $arrayElemAt: ["$clientRec", 0] } }, + in: { + _id: "$$client._id", + pid: "$$client.pid", + name: "$$client.name", + type: "$$client.type", + avatar: "$$client.avatar", + }, + }, + }, + assignedTo: { + $let: { + vars: { assigned: { $arrayElemAt: ["$assignedRec", 0] } }, + in: { + _id: "$$assigned._id", + pid: "$$assigned.pid", + name: "$$assigned.name", + avatar: "$$assigned.avatar", + }, + }, + }, + createdBy: { + $let: { + vars: { created: { $arrayElemAt: ["$createdRec", 0] } }, + in: { + _id: "$$created._id", + pid: "$$created.pid", + name: "$$created.name", + avatar: "$$created.avatar", + }, + }, + }, + }, + }, + { + $facet: { + metadata: [{ $count: "count" }], + data: [ + { $skip: (page - 1) * pageSize }, + { $limit: pageSize }, + { $sort: sortObj }, + ], + }, + }, + ]); + + if (permitsList[0].data.length === 0) + return { permits: [], metadata: { count: 0, page, pageSize } }; + + return { + permits: permitsList[0]?.data, + metadata: { + count: permitsList[0].metadata[0].count, + page, + pageSize, + }, + }; +} + +export async function getUniqueValuesPermit(field: string, tenenatId: string) { let values = await permitModel.distinct(field, { tenantId: tenenatId }); let matchedValues = [];