import { Request, Response, NextFunction } from "express"; import { db } from "@server/db"; import { and, eq, or, inArray } from "drizzle-orm"; import { resources, userResources, roleResources, userOrgs, resourcePassword, resourcePincode, resourceWhitelist } from "@server/db"; import createHttpError from "http-errors"; import HttpCode from "@server/types/HttpCode"; import { response } from "@server/lib/response"; export async function getUserResources( req: Request, res: Response, next: NextFunction ): Promise { try { const { orgId } = req.params; const userId = req.user?.userId; if (!userId) { return next( createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated") ); } // First get the user's role in the organization const userOrgResult = await db .select({ roleId: userOrgs.roleId }) .from(userOrgs) .where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId))) .limit(1); if (userOrgResult.length === 0) { return next( createHttpError(HttpCode.FORBIDDEN, "User not in organization") ); } const userRoleId = userOrgResult[0].roleId; // Get resources accessible through direct assignment or role assignment const directResourcesQuery = db .select({ resourceId: userResources.resourceId }) .from(userResources) .where(eq(userResources.userId, userId)); const roleResourcesQuery = db .select({ resourceId: roleResources.resourceId }) .from(roleResources) .where(eq(roleResources.roleId, userRoleId)); const [directResources, roleResourceResults] = await Promise.all([ directResourcesQuery, roleResourcesQuery ]); // Combine all accessible resource IDs const accessibleResourceIds = [ ...directResources.map((r) => r.resourceId), ...roleResourceResults.map((r) => r.resourceId) ]; if (accessibleResourceIds.length === 0) { return response(res, { data: { resources: [] }, success: true, error: false, message: "No resources found", status: HttpCode.OK }); } // Get resource details for accessible resources const resourcesData = await db .select({ resourceId: resources.resourceId, name: resources.name, fullDomain: resources.fullDomain, ssl: resources.ssl, enabled: resources.enabled, sso: resources.sso, protocol: resources.protocol, emailWhitelistEnabled: resources.emailWhitelistEnabled }) .from(resources) .where( and( inArray(resources.resourceId, accessibleResourceIds), eq(resources.orgId, orgId), eq(resources.enabled, true) ) ); // Check for password, pincode, and whitelist protection for each resource const resourcesWithAuth = await Promise.all( resourcesData.map(async (resource) => { const [passwordCheck, pincodeCheck, whitelistCheck] = await Promise.all([ db .select() .from(resourcePassword) .where( eq( resourcePassword.resourceId, resource.resourceId ) ) .limit(1), db .select() .from(resourcePincode) .where( eq( resourcePincode.resourceId, resource.resourceId ) ) .limit(1), db .select() .from(resourceWhitelist) .where( eq( resourceWhitelist.resourceId, resource.resourceId ) ) .limit(1) ]); const hasPassword = passwordCheck.length > 0; const hasPincode = pincodeCheck.length > 0; const hasWhitelist = whitelistCheck.length > 0 || resource.emailWhitelistEnabled; return { resourceId: resource.resourceId, name: resource.name, domain: `${resource.ssl ? "https://" : "http://"}${resource.fullDomain}`, enabled: resource.enabled, protected: !!( resource.sso || hasPassword || hasPincode || hasWhitelist ), protocol: resource.protocol, sso: resource.sso, password: hasPassword, pincode: hasPincode, whitelist: hasWhitelist }; }) ); return response(res, { data: { resources: resourcesWithAuth }, success: true, error: false, message: "User resources retrieved successfully", status: HttpCode.OK }); } catch (error) { console.error("Error fetching user resources:", error); return next( createHttpError( HttpCode.INTERNAL_SERVER_ERROR, "Internal server error" ) ); } } export type GetUserResourcesResponse = { success: boolean; data: { resources: Array<{ resourceId: number; name: string; domain: string; enabled: boolean; protected: boolean; protocol: string; }>; }; };