import type { H3Event } from 'h3' // Cache for org-role access mapping let orgRoleAccessCache: Map> | null = null let cacheTimestamp: number = 0 const CACHE_DURATION = 5 * 60 * 1000 // 5 minutes interface OrgRecord { id: number AD_Role_OrgAccess?: Array<{ AD_Role_ID?: { id: number } IsActive?: boolean }> } /** * Fetches and caches organization-role access mapping from iDempiere * Returns a Map where: * - Key: Organization ID * - Value: Set of Role IDs that have access to this organization * * Special case: Organization ID 0 (Name: "*") means "All Organizations" */ export async function getOrgRoleAccessMap(event: H3Event): Promise>> { const now = Date.now() // Return cached data if still valid if (orgRoleAccessCache && (now - cacheTimestamp) < CACHE_DURATION) { return orgRoleAccessCache } try { const token = await getTokenHelper(event) // Fetch all organizations with their role access mappings const res: any = await event.context.fetch( 'models/ad_org?$expand=AD_Role_OrgAccess', 'GET', token, null ) if (!res?.records) { console.error('Failed to fetch org-role access data') return orgRoleAccessCache || new Map() } // Build the mapping const accessMap = new Map>() for (const org of res.records as OrgRecord[]) { const orgId = org.id const roleSet = new Set() if (org.AD_Role_OrgAccess && Array.isArray(org.AD_Role_OrgAccess)) { for (const access of org.AD_Role_OrgAccess) { // Only include active role access if (access.IsActive !== false && access.AD_Role_ID?.id) { roleSet.add(access.AD_Role_ID.id) } } } accessMap.set(orgId, roleSet) } // Cache the result orgRoleAccessCache = accessMap cacheTimestamp = now console.log(`[OrgRoleAccessCache] Loaded ${accessMap.size} organizations with role mappings`) return accessMap } catch (error: any) { console.error('[OrgRoleAccessCache] Error fetching org-role access:', error.message) // Return existing cache or empty map on error return orgRoleAccessCache || new Map() } } /** * Checks if a given role has access to a specific organization * Handles the special case where org ID 0 (Name: "*") means "All Organizations" */ export function hasRoleAccessToOrg( orgRoleAccessMap: Map>, roleId: number, orgId: number ): boolean { // Check if role has access to org ID 0 ("*" - All Organizations) const allOrgsRoles = orgRoleAccessMap.get(0) if (allOrgsRoles && allOrgsRoles.has(roleId)) { return true // Role has access to all organizations } // Check if role has access to the specific organization const orgRoles = orgRoleAccessMap.get(orgId) return orgRoles ? orgRoles.has(roleId) : false } /** * Invalidates the cache, forcing a refresh on next access */ export function invalidateOrgRoleAccessCache() { orgRoleAccessCache = null cacheTimestamp = 0 console.log('[OrgRoleAccessCache] Cache invalidated') }