import { Request, Response, NextFunction } from "express"; import { z } from "zod"; import { db } from "@server/db"; import { orgs, resources, roles, sites, userOrgs, userResources, users, userSites } from "@server/db/schemas"; import { and, count, eq, inArray, countDistinct } from "drizzle-orm"; import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; import logger from "@server/logger"; import { fromZodError } from "zod-validation-error"; import { RoleItem } from "../user/getOrgUser"; const getOrgParamsSchema = z .object({ orgId: z.string() }) .strict(); export type GetOrgOverviewResponse = { orgName: string; orgId: string; roles: RoleItem[]; numSites: number; numUsers: number; numResources: number; isAdmin: boolean; isOwner: boolean; }; export async function getOrgOverview( req: Request, res: Response, next: NextFunction ): Promise { try { const parsedParams = getOrgParamsSchema.safeParse(req.params); if (!parsedParams.success) { return next( createHttpError( HttpCode.BAD_REQUEST, fromZodError(parsedParams.error) ) ); } const { orgId } = parsedParams.data; const org = await db .select() .from(orgs) .where(eq(orgs.orgId, orgId)) .limit(1); if (org.length === 0) { return next( createHttpError( HttpCode.NOT_FOUND, `Organization with ID ${orgId} not found` ) ); } if (!req.userOrg) { return next( createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated") ); } const allSiteIds = await db .select({ siteId: sites.siteId }) .from(sites) .where(eq(sites.orgId, orgId)); const [{ numSites }] = await db .select({ numSites: count() }) .from(userSites) .where( and( eq(userSites.userId, req.userOrg.userId), inArray( userSites.siteId, allSiteIds.map((site) => site.siteId) ) ) ); const allResourceIds = await db .select({ resourceId: resources.resourceId }) .from(resources) .where(eq(resources.orgId, orgId)); const [{ numResources }] = await db .select({ numResources: count() }) .from(userResources) .where( and( eq(userResources.userId, req.userOrg.userId), inArray( userResources.resourceId, allResourceIds.map((resource) => resource.resourceId) ) ) ); const [{ numUsers }] = await db .select({ numUsers: countDistinct(userOrgs.userId) }) .from(userOrgs) .where(eq(userOrgs.orgId, orgId)); const userRoles = await db .select({ id: roles.roleId, name: roles.name }) .from(roles) .where(inArray(roles.roleId, req.userRoleIds ?? [])) .orderBy(roles.name); return response(res, { data: { orgName: org[0].name, orgId: org[0].orgId, roles: userRoles, numSites, numUsers, numResources, isAdmin: userRoles.some((r) => r.name === "Admin"), isOwner: req.userOrg?.isOwner || false }, success: true, error: false, message: "Organization overview retrieved successfully", status: HttpCode.OK }); } catch (error) { logger.error(error); return next( createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred") ); } }