diff --git a/npm/src/controller/admin.ts b/npm/src/controller/admin.ts index b7a409bb3..b5ecadc12 100644 --- a/npm/src/controller/admin.ts +++ b/npm/src/controller/admin.ts @@ -65,4 +65,12 @@ export class AdminController implements IAdminController { ) { return await this.ssoTracer.getTracesByProduct({ product, pageOffset, pageLimit, pageToken }); } + + public async deleteTracesByProduct(product: string) { + return await this.ssoTracer.deleteTracesByProduct(product); + } + + public async countByProduct(product: string) { + return await this.ssoTracer.countByProduct(product); + } } diff --git a/npm/src/sso-tracer/index.ts b/npm/src/sso-tracer/index.ts index c486cef2f..27e2a7e12 100644 --- a/npm/src/sso-tracer/index.ts +++ b/npm/src/sso-tracer/index.ts @@ -206,6 +206,31 @@ class SSOTracer { return traces; } + + public async deleteTracesByProduct(product: string) { + let pageToken; + do { + const res = await this.getTracesByProduct({ + product, + pageOffset: 0, + pageLimit: 50, + }); + if (!res.data || !res.data.length) { + break; + } + pageToken = res.pageToken; + // deleting traces in batches of 50 + // deleting in the loop right away as we get the traces + await this.tracerStore.deleteMany((res.data || []).map((t) => t.traceId)); + } while (pageToken); + } + + public async countByProduct(product: string) { + return await this.tracerStore.getCount({ + name: IndexNames.Product, + value: product, + }); + } } export default SSOTracer; diff --git a/npm/src/typings.ts b/npm/src/typings.ts index 4835d23f0..69e2ddcf3 100644 --- a/npm/src/typings.ts +++ b/npm/src/typings.ts @@ -212,6 +212,7 @@ export interface IAdminController { getAllSSOTraces(pageOffset: number, pageLimit: number, pageToken?: string); getSSOTraceById(traceId: string); getTracesByProduct(product: string, pageOffset: number, pageLimit: number, pageToken?: string); + deleteTracesByProduct(product: string); } export interface IHealthCheckController { diff --git a/pages/api/v1/sso-traces/product.ts b/pages/api/v1/sso-traces/product/count.ts similarity index 75% rename from pages/api/v1/sso-traces/product.ts rename to pages/api/v1/sso-traces/product/count.ts index 6e8295a69..f898ebfad 100644 --- a/pages/api/v1/sso-traces/product.ts +++ b/pages/api/v1/sso-traces/product/count.ts @@ -1,5 +1,4 @@ import jackson from '@lib/jackson'; -import { parsePaginateApiParams } from '@lib/utils'; import { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -26,9 +25,7 @@ const handleGET = async (req: NextApiRequest, res: NextApiResponse) => { product: string; }; - const { pageOffset, pageLimit, pageToken } = parsePaginateApiParams(req.query); + const count = await adminController.countByProduct(product); - const traces = await adminController.getTracesByProduct(product, pageOffset, pageLimit, pageToken); - - res.json(traces); + res.json({ count }); }; diff --git a/pages/api/v1/sso-traces/product/index.ts b/pages/api/v1/sso-traces/product/index.ts new file mode 100644 index 000000000..feb028fc5 --- /dev/null +++ b/pages/api/v1/sso-traces/product/index.ts @@ -0,0 +1,49 @@ +import jackson from '@lib/jackson'; +import { parsePaginateApiParams } from '@lib/utils'; +import { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + switch (req.method) { + case 'GET': + await handleGET(req, res); + break; + case 'DELETE': + await handleDelete(req, res); + break; + default: + res.setHeader('Allow', 'GET,DELETE'); + res.status(405).json({ error: { message: `Method ${req.method} Not Allowed` } }); + } + } catch (error: any) { + const { message, statusCode = 500 } = error; + res.status(statusCode).json({ error: { message } }); + } +} + +// Get the sso traces filtered by the product +const handleGET = async (req: NextApiRequest, res: NextApiResponse) => { + const { adminController } = await jackson(); + + const { product } = req.query as { + product: string; + }; + + const { pageOffset, pageLimit, pageToken } = parsePaginateApiParams(req.query); + + const traces = await adminController.getTracesByProduct(product, pageOffset, pageLimit, pageToken); + + res.json(traces); +}; + +const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => { + const { adminController } = await jackson(); + + const { product } = req.query as { + product: string; + }; + + await adminController.deleteTracesByProduct(product); + + res.status(204).end(); +};