1import { 2 UserManagementService, 3 init_permission_config, 4 permission_config_exports 5} from "./chunk-IMGOCUIU.js"; 6import { 7 BehaviorSubject, 8 Injectable, 9 forkJoin, 10 retry, 11 setClassMetadata, 12 shareReplay, 13 timer, 14 ɵɵdefineInjectable, 15 ɵɵinject 16} from "./chunk-6GJQIPT2.js"; 17import { 18 __toCommonJS 19} from "./chunk-RK4NW2NR.js"; 20
21// src/app/utils/retry-transient.ts 22function isTransientHttpError(error) { 23 const status = error?.status ?? 0; 24 return status === 0 || status === 408 || status === 429 || status >= 500; 25} 26function retryTransient(count = 2, baseDelayMs = 800) { 27 return retry({ 28 count, 29 delay: (error, attempt) => { 30 if (!isTransientHttpError(error)) { 31 throw error; 32 } 33 return timer(attempt * baseDelayMs); 34 } 35 }); 36} 37
38// src/app/services/permission.service.ts 39var normalizeCode = (input) => (input ?? "").toUpperCase().trim().replace(/[\s-]+/g, "_"); 40var normalizePermissions = (raw) => { 41 const set = /* @__PURE__ */ new Set(); 42 for (const p of raw || []) { 43 const normalized = normalizeCode(p); 44 if (normalized) { 45 set.add(normalized); 46 } 47 } 48 return Array.from(set); 49}; 50var currentRoles = /* @__PURE__ */ new Set(); 51var currentPermissions = /* @__PURE__ */ new Set(); 52var currentGroups = /* @__PURE__ */ new Set(); 53var setPermissionContext = (input) => { 54 const roleCodes = new Set(normalizePermissions(input.roles ?? [])); 55 const groupCodes = new Set(normalizePermissions(input.permissionGroups ?? [])); 56 const permissionCodes = new Set(normalizePermissions(input.permissions ?? [])); 57 currentRoles = roleCodes; 58 currentGroups = groupCodes; 59 currentPermissions = permissionCodes; 60}; 61var hasPermission = (permission) => { 62 const isSuperAdminUser = ["SUPER_ADMIN", "SUPERADMIN"].some((r) => currentRoles.has(r)); 63 if (isSuperAdminUser) 64 return true; 65 const code = normalizeCode(permission); 66 if (!code) 67 return false; 68 if (currentPermissions.has(code)) 69 return true; 70 if (code.includes("PERMISSIONGROUP")) { 71 const fallbackCode = code.replace("PERMISSIONGROUP", "PERMISSION_GROUP"); 72 if (currentPermissions.has(fallbackCode)) 73 return true; 74 } 75 if (code.includes("PERMISSION_GROUP")) { 76 const fallbackCode = code.replace("PERMISSION_GROUP", "PERMISSIONGROUP"); 77 if (currentPermissions.has(fallbackCode)) 78 return true; 79 } 80 return false; 81}; 82var hasAny = (permissions) => { 83 for (const p of permissions || []) { 84 if (hasPermission(p)) 85 return true; 86 } 87 return false; 88}; 89var hasGroup = (group) => { 90 const code = normalizeCode(group); 91 if (!code) 92 return false; 93 return currentGroups.has(code); 94}; 95var hasRole = (role) => { 96 const code = normalizeCode(role); 97 if (!code) { 98 return false; 99 } 100 const result = currentRoles.has(code); 101 return result; 102}; 103var PermissionService = class _PermissionService { 104 userManagementService; 105 currentUserProfile$ = new BehaviorSubject(null); 106 isSessionReady$ = new BehaviorSubject(false); 107 // Layout, PageHeader and other shells all bootstrap the profile from the same 108 // users+roles pair on load. Without sharing the in-flight request each of them 109 // fires its own HTTP call, tripling the /api/users and /api/roles hits on every 110 // page load. Caching here collapses concurrent/duplicate callers onto one call. 111 usersAndRoles$ = null; 112 constructor(userManagementService) { 113 this.userManagementService = userManagementService; 114 } 115 loadUsersAndRoles() { 116 if (!this.usersAndRoles$) { 117 this.usersAndRoles$ = forkJoin({ 118 users: this.userManagementService.getUsers(), 119 roles: this.userManagementService.getRoles() 120 }).pipe(retryTransient(), shareReplay(1)); 121 } 122 return this.usersAndRoles$; 123 } 124 /** Call before loadUsersAndRoles() when a caller needs a guaranteed-fresh fetch (e.g. after an IAM change push). */ 125 invalidateUsersAndRolesCache() { 126 this.usersAndRoles$ = null; 127 } 128 setSessionReady(ready) { 129 this.isSessionReady$.next(ready); 130 } 131 setUserProfile(user) { 132 this.currentUserProfile$.next(user); 133 if (!user) { 134 this.setSessionReady(false); 135 } 136 if (user) { 137 const roles = user.roles.map((r) => normalizeCode(r.name)); 138 const roleGroups = user.roles.flatMap((r) => r.permissionGroups?.map((g) => normalizeCode(g.name)) ?? []); 139 const directGroups = user.permissionGroups?.map((g) => normalizeCode(g.name)) ?? []; 140 const permissionGroups = [...roleGroups, ...directGroups]; 141 const rolePermissions = user.roles.flatMap((r) => [ 142 ...r.permissions.map((p) => normalizeCode(p.name)), 143 ...r.permissionGroups.flatMap((g) => g.permissions.map((p) => normalizeCode(p.name))) 144 ]); 145 const directPermissions = user.permissionGroups?.flatMap((g) => g.permissions?.map((p) => normalizeCode(p.name)) ?? []) ?? []; 146 const permissions = [...rolePermissions, ...directPermissions]; 147 setPermissionContext({ roles, permissionGroups, permissions }); 148 } else { 149 setPermissionContext({ roles: [], permissionGroups: [], permissions: [] }); 150 } 151 } 152 getUserProfile() { 153 return this.currentUserProfile$.asObservable(); 154 } 155 getCurrentUserProfile() { 156 return this.currentUserProfile$.value; 157 } 158 hasPermission(permissionName) { 159 return hasPermission(permissionName); 160 } 161 hasAnyPermission(permissionNames) { 162 return hasAny(permissionNames); 163 } 164 hasRole(roleName) { 165 return hasRole(roleName); 166 } 167 hasGroup(groupName) { 168 return hasGroup(groupName); 169 } 170 isSuperAdmin() { 171 const { ROLE_TYPES } = (init_permission_config(), __toCommonJS(permission_config_exports
171)); 172 return ROLE_TYPES.SUPER_ADMIN.some((roleName) => hasRole(roleName)); 173 } 174 isAdmin() { 175 const { ROLE_TYPES } = (init_permission_config(), __toCommonJS(permission_config_exports)); 176 return ROLE_TYPES.ADMIN.some((roleName) => hasRole(roleName)); 177 } 178 isViewer() { 179 const { ROLE_TYPES } = (init_permission_config(), __toCommonJS(permission_config_exports)); 180 return ROLE_TYPES.VIEWER.some((roleName) => hasRole(roleName)); 181 } 182 /** 183 * Check if user has a specific role type (configured in permission-config) 184 */ 185 hasRoleType(roleType) { 186 const { ROLE_TYPES } = (init_permission_config(), __toCommonJS(permission_config_exports)); 187 const roleNames = ROLE_TYPES[roleType]; 188 if (!roleNames) 189 return false; 190 return roleNames.some((roleName) => hasRole(roleName)); 191 } 192 /** 193 * Get all permissions for the current user 194 */ 195 getAllPermissions() { 196 return Array.from(currentPermissions); 197 } 198 /** 199 * Get all permission groups for the current user 200 */ 201 getAllGroups() { 202 return Array.from(currentGroups); 203 } 204 /** 205 * Get all roles for the current user 206 */ 207 getAllRoles() { 208 return Array.from(currentRoles); 209 } 210 /** 211 * Debug helper: Get detailed permission information 212 * Useful for troubleshooting permission issues 213 */ 214 getPermissionDebugInfo() { 215 const profile = this.getCurrentUserProfile(); 216 return { 217 roles: this.getAllRoles(), 218 permissionGroups: this.getAllGroups(), 219 permissions: this.getAllPermissions(), 220 userProfile: profile, 221 hasDeleteRfpCard: this.hasPermission("DELETE_RFP_CARD"), 222 hasDeleteRole: this.hasPermission("DELETE_ROLE"), 223 hasDeletePermission: this.hasPermission("DELETE_PERMISSION") 224 }; 225 } 226 static \u0275fac = function PermissionService_Factory(__ngFactoryType__) { 227 return new (__ngFactoryType__ || _PermissionService)(\u0275\u0275inject(UserManagementService)); 228 }; 229 static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _PermissionService, factory: _PermissionService.\u0275fac, providedIn: "root" }); 230}; 231(() => { 232 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PermissionService, [{ 233 type: Injectable, 234 args: [{ 235 providedIn: "root" 236 }] 237 }], () => [{ type: UserManagementService }], null); 238})(); 239 240export { 241 isTransientHttpError, 242 PermissionService 243}; 244//# sourceMappingURL=chunk-5PIXT7LD.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.