diff --git a/bruno/Auth/login.bru b/bruno/Auth/login.bru new file mode 100644 index 00000000..25e6406e --- /dev/null +++ b/bruno/Auth/login.bru @@ -0,0 +1,11 @@ +meta { + name: login + type: http + seq: 1 +} + +get { + url: + body: none + auth: none +} diff --git a/bruno/Orgs/listOrgs.bru b/bruno/Orgs/listOrgs.bru new file mode 100644 index 00000000..89c34d0c --- /dev/null +++ b/bruno/Orgs/listOrgs.bru @@ -0,0 +1,11 @@ +meta { + name: listOrgs + type: http + seq: 1 +} + +get { + url: + body: none + auth: none +} diff --git a/bruno/Resources/listResourcesByOrg.bru b/bruno/Resources/listResourcesByOrg.bru new file mode 100644 index 00000000..6efce1b2 --- /dev/null +++ b/bruno/Resources/listResourcesByOrg.bru @@ -0,0 +1,11 @@ +meta { + name: listResourcesByOrg + type: http + seq: 1 +} + +get { + url: + body: none + auth: none +} diff --git a/bruno/Resources/listResourcesBySite.bru b/bruno/Resources/listResourcesBySite.bru new file mode 100644 index 00000000..81c9cf99 --- /dev/null +++ b/bruno/Resources/listResourcesBySite.bru @@ -0,0 +1,16 @@ +meta { + name: listResourcesBySite + type: http + seq: 2 +} + +get { + url: http://localhost:3000/api/v1/site/1/resources?limit=10&offset=0 + body: none + auth: none +} + +params:query { + limit: 10 + offset: 0 +} diff --git a/bruno/Sites/listSites.bru b/bruno/Sites/listSites.bru new file mode 100644 index 00000000..b7912330 --- /dev/null +++ b/bruno/Sites/listSites.bru @@ -0,0 +1,11 @@ +meta { + name: listSites + type: http + seq: 1 +} + +get { + url: + body: none + auth: none +} diff --git a/bruno/Targets/listTargets.bru b/bruno/Targets/listTargets.bru new file mode 100644 index 00000000..7981eb45 --- /dev/null +++ b/bruno/Targets/listTargets.bru @@ -0,0 +1,16 @@ +meta { + name: listTargets + type: http + seq: 1 +} + +get { + url: http://localhost:3000/api/v1/resource/web.main.localhost/targets?limit=10&offset=0 + body: none + auth: none +} + +params:query { + limit: 10 + offset: 0 +} diff --git a/bruno/bruno.json b/bruno/bruno.json new file mode 100644 index 00000000..c28a54bb --- /dev/null +++ b/bruno/bruno.json @@ -0,0 +1,9 @@ +{ + "version": "1", + "name": "Pangolin", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ] +} \ No newline at end of file diff --git a/server/auth/limits.ts b/server/auth/limits.ts new file mode 100644 index 00000000..4eb06490 --- /dev/null +++ b/server/auth/limits.ts @@ -0,0 +1,40 @@ +import { db } from '@server/db'; +import { limitsTable } from '@server/db/schema'; +import { and, eq } from 'drizzle-orm'; +import createHttpError from 'http-errors'; +import HttpCode from '@server/types/HttpCode'; + +interface CheckLimitOptions { + orgId: number; + limitName: string; + currentValue: number; + increment?: number; +} + +export async function checkOrgLimit({ orgId, limitName, currentValue, increment = 0 }: CheckLimitOptions): Promise { + try { + const limit = await db.select() + .from(limitsTable) + .where( + and( + eq(limitsTable.orgId, orgId), + eq(limitsTable.name, limitName) + ) + ) + .limit(1); + + if (limit.length === 0) { + throw createHttpError(HttpCode.NOT_FOUND, `Limit "${limitName}" not found for organization`); + } + + const limitValue = limit[0].value; + + // Check if the current value plus the increment is within the limit + return (currentValue + increment) <= limitValue; + } catch (error) { + if (error instanceof Error) { + throw createHttpError(HttpCode.INTERNAL_SERVER_ERROR, `Error checking limit: ${error.message}`); + } + throw createHttpError(HttpCode.INTERNAL_SERVER_ERROR, 'Unknown error occurred while checking limit'); + } +} \ No newline at end of file diff --git a/server/db/schema.ts b/server/db/schema.ts index 46b264b1..c9408d2a 100644 --- a/server/db/schema.ts +++ b/server/db/schema.ts @@ -202,6 +202,14 @@ export const userResources = sqliteTable("userResources", { .references(() => resources.resourceId, { onDelete: "cascade" }), }); +export const limitsTable = sqliteTable("limits", { + limitId: integer("limitId").primaryKey({ autoIncrement: true }), + orgId: integer("orgId").references(() => orgs.orgId, { onDelete: "cascade" }), + name: text("name").notNull(), + value: integer("value").notNull(), + description: text("description"), +}); + // Define the model types for type inference export type Org = InferSelectModel; export type User = InferSelectModel; @@ -223,4 +231,5 @@ export type UserAction = InferSelectModel; export type RoleSite = InferSelectModel; export type UserSite = InferSelectModel; export type RoleResource = InferSelectModel; -export type UserResource = InferSelectModel; \ No newline at end of file +export type UserResource = InferSelectModel; +export type Limit = InferSelectModel; \ No newline at end of file diff --git a/server/routers/target/listTargets.ts b/server/routers/target/listTargets.ts index 1e4ecc73..0dd2de52 100644 --- a/server/routers/target/listTargets.ts +++ b/server/routers/target/listTargets.ts @@ -73,8 +73,7 @@ export async function listTargets(req: Request, res: Response, next: NextFunctio const totalCountResult = await countQuery; const totalCount = totalCountResult[0].count; - return res.status(HttpCode.OK).send( - response(res, { + return response(res, { data: { targets: targetsList, pagination: { @@ -88,8 +87,9 @@ export async function listTargets(req: Request, res: Response, next: NextFunctio message: "Targets retrieved successfully", status: HttpCode.OK, }) - ); } catch (error) { - next(error); + console.log(error); + + return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "sadfdf")); } } \ No newline at end of file