@open-rlb/ng-app 3.1.9 → 3.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@ import { provideServiceWorker } from '@angular/service-worker';
9
9
  import * as i1$8 from '@ngrx/effects';
10
10
  import { createEffect, ofType, provideEffects } from '@ngrx/effects';
11
11
  import * as i1$1 from '@ngrx/store';
12
- import { createActionGroup, props, emptyProps, createFeature, createReducer, on, provideStore, provideState } from '@ngrx/store';
12
+ import { createActionGroup, props, emptyProps, Store, createFeature, createReducer, on, provideStore, provideState } from '@ngrx/store';
13
13
  import * as i2$1 from '@open-rlb/ng-bootstrap';
14
14
  import { RLB_TRANSLATION_SERVICE, RlbBootstrapModule, ModalDirective, ToastDirective, ModalRegistryOptions, ToastRegistryOptions, provideRlbBootstrap } from '@open-rlb/ng-bootstrap';
15
15
  import * as i1$5 from 'angular-auth-oidc-client';
@@ -35,6 +35,7 @@ const RLB_CFG_PAGES = new InjectionToken(`${RLB_CFG}:pages`);
35
35
  const RLB_CFG_ENV = new InjectionToken(`${RLB_CFG}:env`);
36
36
  const RLB_CFG_AUTH = new InjectionToken(`${RLB_CFG}:auth`);
37
37
  const RLB_APP_NAVCOMP = new InjectionToken(`rlb.app.navcomp`);
38
+ const RLB_CFG_ACL = new InjectionToken(`${RLB_CFG}:acl`);
38
39
 
39
40
  class TokenCookiesService {
40
41
  constructor(cookies) {
@@ -390,6 +391,24 @@ const initialSidebarState = {
390
391
  searchText: null
391
392
  };
392
393
 
394
+ const AclActions = createActionGroup({
395
+ source: 'ACL',
396
+ events: {
397
+ 'Load ACL': emptyProps(),
398
+ 'Load ACL Success': props(),
399
+ 'Load ACL Failure': props(),
400
+ 'Reset': emptyProps(),
401
+ }
402
+ });
403
+
404
+ const aclFeatureKey = 'acl';
405
+ const initialAclState = {
406
+ resources: null,
407
+ loading: false,
408
+ loaded: false,
409
+ error: null
410
+ };
411
+
393
412
  class AbstractSupportService {
394
413
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AbstractSupportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
395
414
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AbstractSupportService }); }
@@ -1361,8 +1380,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
1361
1380
  }]
1362
1381
  }] });
1363
1382
 
1383
+ class AdminApiService {
1384
+ constructor(httpClient, config, aclConfig) {
1385
+ this.httpClient = httpClient;
1386
+ this.config = config;
1387
+ this.aclConfig = aclConfig;
1388
+ }
1389
+ resourcesByUser$() {
1390
+ if (!this.aclConfig) {
1391
+ throw new Error("ACL configuration is missing. Provide 'acl' in ProjectConfiguration.");
1392
+ }
1393
+ const endpoint = this.config.endpoints?.[this.aclConfig.endpointKey];
1394
+ if (!endpoint) {
1395
+ throw new Error(`Endpoint '${this.aclConfig.endpointKey}' not found in configuration.`);
1396
+ }
1397
+ const url = `${endpoint.baseUrl}/${this.aclConfig.path}`;
1398
+ return this.httpClient.get(url).pipe(
1399
+ //this.errorManagementService.manageUI('error', 'dialog')
1400
+ );
1401
+ }
1402
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AdminApiService, deps: [{ token: i1$3.HttpClient }, { token: RLB_CFG, optional: true }, { token: RLB_CFG_ACL, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1403
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AdminApiService, providedIn: 'root' }); }
1404
+ }
1405
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AdminApiService, decorators: [{
1406
+ type: Injectable,
1407
+ args: [{ providedIn: 'root' }]
1408
+ }], ctorParameters: () => [{ type: i1$3.HttpClient }, { type: undefined, decorators: [{
1409
+ type: Optional
1410
+ }, {
1411
+ type: Inject,
1412
+ args: [RLB_CFG]
1413
+ }] }, { type: undefined, decorators: [{
1414
+ type: Optional
1415
+ }, {
1416
+ type: Inject,
1417
+ args: [RLB_CFG_ACL]
1418
+ }] }] });
1419
+
1364
1420
  class AuthenticationService {
1365
- constructor(oidcSecurityService, cookiesService, router, parseJwtService, store, log, localStorage, envConfig, authConfig) {
1421
+ constructor(oidcSecurityService, cookiesService, router, parseJwtService, store, log, localStorage, adminApi, envConfig, authConfig, appconfig) {
1366
1422
  this.oidcSecurityService = oidcSecurityService;
1367
1423
  this.cookiesService = cookiesService;
1368
1424
  this.router = router;
@@ -1370,8 +1426,10 @@ class AuthenticationService {
1370
1426
  this.store = store;
1371
1427
  this.log = log;
1372
1428
  this.localStorage = localStorage;
1429
+ this.adminApi = adminApi;
1373
1430
  this.envConfig = envConfig;
1374
1431
  this.authConfig = authConfig;
1432
+ this.appconfig = appconfig;
1375
1433
  this.logger = this.log.for(this.constructor.name);
1376
1434
  this.logger.log('AuthenticationService initialized');
1377
1435
  }
@@ -1386,45 +1444,27 @@ class AuthenticationService {
1386
1444
  return this.authConfig?.providers.find((provider) => provider.configId === currentProvider);
1387
1445
  }
1388
1446
  checkAuthMultiple(url) {
1389
- // if (Capacitor.isNativePlatform()) {
1390
- // console.log('Capacitor is native platform')
1391
- // App.addListener('appUrlOpen', async ({ url }: { url: string }) => {
1392
- // await this.zone.run(async () => {
1393
- // const _url = `${environment.baseUrl}/${url.slice(url.indexOf('?'))}`
1394
- // this.authorize(_url).subscribe();
1395
- // })
1396
- // });
1397
- // } else {
1398
- return this.oidc.checkAuthMultiple(url)
1399
- .pipe(tap(data => {
1400
- const authenticatedConfig = data.find(o => o.isAuthenticated);
1447
+ return this.oidc.checkAuthMultiple(url).pipe(switchMap((responses) => {
1448
+ const authenticatedConfig = responses.find(o => o.isAuthenticated);
1401
1449
  if (authenticatedConfig && authenticatedConfig.configId) {
1402
- this.logger.info(`User is authenticated with provider: ${authenticatedConfig.configId}. Updating Store.`);
1403
- // first dispatch to prevent recalculate in apps service
1404
1450
  this.store.dispatch(AuthActions.setCurrentProvider({
1405
1451
  currentProvider: authenticatedConfig.configId
1406
1452
  }));
1407
- const redirect = this.localStorage.readLocal('loginRedirectUrl');
1408
- //const redirect = this.cookiesService.getCookie('loginRedirectUrl');
1409
- this.logger.info(`Correct provider dispatched, redirectUrl: ${redirect}`);
1410
- if (redirect) {
1411
- this.localStorage.removeLocal('loginRedirectUrl');
1412
- // this.cookiesService.deleteCookie('loginRedirectUrl');
1413
- // setTimeout to prevent NavigationCancel
1414
- // this allows current angular navigation cycle (handle URL with code/state) to complete
1415
- setTimeout(() => {
1416
- this.router.navigateByUrl(redirect, { replaceUrl: true });
1417
- }, 0);
1453
+ // Only fetch ACL if config is provided
1454
+ if (this.appconfig.acl) {
1455
+ this.store.dispatch(AclActions.loadACL());
1456
+ return this.adminApi.resourcesByUser$().pipe(tap(resources => {
1457
+ this.store.dispatch(AclActions.loadACLSuccess({ resources }));
1458
+ this.handleRedirect();
1459
+ }), map(() => responses), catchError(() => of(responses)));
1418
1460
  }
1419
1461
  else {
1420
- this.logger.info(`User authenticated, no redirectUrl found. Staying on current route.`);
1462
+ this.handleRedirect();
1463
+ return of(responses);
1421
1464
  }
1422
1465
  }
1423
- else {
1424
- this.logger.warn(`No authenticatedConfig found for ${url}`);
1425
- }
1466
+ return of(responses);
1426
1467
  }));
1427
- //}
1428
1468
  }
1429
1469
  login(targetUrl) {
1430
1470
  const returnUrl = targetUrl || this.router.url || '/';
@@ -1487,7 +1527,16 @@ class AuthenticationService {
1487
1527
  matchRoles(roles) {
1488
1528
  return this.accessToken$.pipe(map(token => this.parseJwtService.parseJwt(token)), map(payload => payload['roles']), map(userRoles => roles.some(role => userRoles.includes(role))));
1489
1529
  }
1490
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthenticationService, deps: [{ token: i1$5.OidcSecurityService }, { token: CookiesService }, { token: i2.Router }, { token: ParseJwtService }, { token: i1$1.Store }, { token: AppLoggerService }, { token: AppStorageService }, { token: RLB_CFG_ENV, optional: true }, { token: RLB_CFG_AUTH, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1530
+ handleRedirect() {
1531
+ const redirect = this.localStorage.readLocal('loginRedirectUrl');
1532
+ if (redirect) {
1533
+ this.localStorage.removeLocal('loginRedirectUrl');
1534
+ setTimeout(() => {
1535
+ this.router.navigateByUrl(redirect, { replaceUrl: true });
1536
+ }, 0);
1537
+ }
1538
+ }
1539
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthenticationService, deps: [{ token: i1$5.OidcSecurityService }, { token: CookiesService }, { token: i2.Router }, { token: ParseJwtService }, { token: i1$1.Store }, { token: AppLoggerService }, { token: AppStorageService }, { token: AdminApiService }, { token: RLB_CFG_ENV, optional: true }, { token: RLB_CFG_AUTH, optional: true }, { token: RLB_CFG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1491
1540
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthenticationService, providedIn: 'root' }); }
1492
1541
  }
1493
1542
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthenticationService, decorators: [{
@@ -1495,7 +1544,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
1495
1544
  args: [{
1496
1545
  providedIn: 'root'
1497
1546
  }]
1498
- }], ctorParameters: () => [{ type: i1$5.OidcSecurityService }, { type: CookiesService }, { type: i2.Router }, { type: ParseJwtService }, { type: i1$1.Store }, { type: AppLoggerService }, { type: AppStorageService }, { type: undefined, decorators: [{
1547
+ }], ctorParameters: () => [{ type: i1$5.OidcSecurityService }, { type: CookiesService }, { type: i2.Router }, { type: ParseJwtService }, { type: i1$1.Store }, { type: AppLoggerService }, { type: AppStorageService }, { type: AdminApiService }, { type: undefined, decorators: [{
1499
1548
  type: Optional
1500
1549
  }, {
1501
1550
  type: Inject,
@@ -1505,6 +1554,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
1505
1554
  }, {
1506
1555
  type: Inject,
1507
1556
  args: [RLB_CFG_AUTH]
1557
+ }] }, { type: undefined, decorators: [{
1558
+ type: Optional
1559
+ }, {
1560
+ type: Inject,
1561
+ args: [RLB_CFG]
1508
1562
  }] }] });
1509
1563
 
1510
1564
  class TokenOauthInterceptor {
@@ -2439,6 +2493,35 @@ const oauthGuard = (route, state) => {
2439
2493
  }));
2440
2494
  };
2441
2495
 
2496
+ const permissionGuard = (route) => {
2497
+ console.log("permission guard", route);
2498
+ const store = inject(Store);
2499
+ const router = inject(Router);
2500
+ // Get requirements from route data
2501
+ const requiredResource = route.data['resource'];
2502
+ const requiredAction = route.data['action'];
2503
+ return store.select(state => state[aclFeatureKey]).pipe(
2504
+ // Wait until the Initializer/Effect has actually finished loading the data
2505
+ filter((acl) => acl.loaded), take(1), map((acl) => {
2506
+ console.log("permission guard map", JSON.stringify(acl));
2507
+ if (!acl.resources)
2508
+ return router.createUrlTree(['/not-found']);
2509
+ const hasPermission = acl.resources.some(product => product.resources.some(res => {
2510
+ const matchName = res.resourceId === requiredResource || res.resourceName === requiredResource;
2511
+ if (!requiredAction) {
2512
+ return matchName;
2513
+ }
2514
+ return matchName && res.actions.includes(requiredAction);
2515
+ }));
2516
+ if (hasPermission) {
2517
+ return true;
2518
+ }
2519
+ // Redirect on failure
2520
+ console.warn(`Access denied for resource: ${requiredResource}`);
2521
+ return router.createUrlTree(['/notFound']);
2522
+ }));
2523
+ };
2524
+
2442
2525
  const SESSION_RT = 'RT';
2443
2526
  const SESSION_AT = 'AT';
2444
2527
  const TOKEN_URL = `protocol/openid-connect/token`;
@@ -2985,7 +3068,7 @@ const authsFeature = createFeature({
2985
3068
  }))
2986
3069
  });
2987
3070
  const authReducer = authsFeature.reducer;
2988
- const { selectAuthState, selectCurrentProvider, selectLoading } = authsFeature;
3071
+ const { selectAuthState, selectCurrentProvider, selectLoading: selectLoading$1 } = authsFeature;
2989
3072
 
2990
3073
  const navbarsFeature = createFeature({
2991
3074
  name: navbarsFeatureKey,
@@ -3076,6 +3159,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
3076
3159
  }]
3077
3160
  }] });
3078
3161
 
3162
+ class AclEffects {
3163
+ constructor(actions$, adminApi) {
3164
+ this.actions$ = actions$;
3165
+ this.adminApi = adminApi;
3166
+ this.loadAclOnAuth$ = createEffect(() => {
3167
+ return this.actions$.pipe(
3168
+ // Listen for the action dispatched in AuthenticationService.checkAuthMultiple
3169
+ ofType(AuthActions.setCurrentProvider), map$1(() => AclActions.loadACL()));
3170
+ });
3171
+ this.fetchAcl$ = createEffect(() => {
3172
+ return this.actions$.pipe(ofType(AclActions.loadACL), switchMap$1(() => this.adminApi.resourcesByUser$().pipe(map$1(resources => AclActions.loadACLSuccess({ resources })), catchError(error => of(AclActions.loadACLFailure({ error }))))));
3173
+ });
3174
+ }
3175
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AclEffects, deps: [{ token: i1$8.Actions }, { token: AdminApiService }], target: i0.ɵɵFactoryTarget.Injectable }); }
3176
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AclEffects }); }
3177
+ }
3178
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AclEffects, decorators: [{
3179
+ type: Injectable
3180
+ }], ctorParameters: () => [{ type: i1$8.Actions }, { type: AdminApiService }] });
3181
+
3182
+ const aclFeature = createFeature({
3183
+ name: aclFeatureKey,
3184
+ reducer: createReducer(initialAclState, on(AclActions.loadACL, (state) => ({
3185
+ ...state,
3186
+ loading: true,
3187
+ loaded: false
3188
+ })), on(AclActions.loadACLSuccess, (state, { resources }) => ({
3189
+ ...state,
3190
+ resources,
3191
+ loaded: true,
3192
+ loading: false
3193
+ })), on(AclActions.loadACLFailure, (state, { error }) => ({
3194
+ ...state,
3195
+ error,
3196
+ loading: false,
3197
+ loaded: true // We mark as loaded to unblock the UI even if the fetch fails
3198
+ })), on(AclActions.reset, () => ({ ...initialAclState })))
3199
+ });
3200
+ const aclReducer = aclFeature.reducer;
3201
+ const { selectAclState, selectResources, selectLoading, selectLoaded } = aclFeature;
3202
+
3079
3203
  const verifyDeactivate = (component, currentRoute, currentState, nextState) => {
3080
3204
  return component.verifyDeactivate();
3081
3205
  };
@@ -3086,11 +3210,12 @@ function provideRlbConfig(env) {
3086
3210
  RlbAppModule,
3087
3211
  provideStore(),
3088
3212
  provideState(authsFeature),
3089
- provideEffects(AuthEffects),
3213
+ provideEffects(AuthEffects, AppContextEffects, AclEffects),
3090
3214
  provideState(navbarsFeature),
3091
3215
  provideState(sidebarsFeature),
3092
3216
  provideState(appFeature),
3093
- provideEffects(AppContextEffects),
3217
+ provideState(aclFeature),
3218
+ // provideEffects(AppContextEffects),
3094
3219
  provideRouter(getDefaultRoutes(env.pages)),
3095
3220
  provideRlbCodeBrowserOAuth(env.auth),
3096
3221
  provideRlbI18n(env.i18n),
@@ -3111,6 +3236,7 @@ function provideRlbConfig(env) {
3111
3236
  { provide: RLB_CFG_CMS, useValue: env.cms },
3112
3237
  { provide: RLB_CFG_PAGES, useValue: env.pages },
3113
3238
  { provide: RLB_CFG_I18N, useValue: env.i18n },
3239
+ { provide: RLB_CFG_ACL, useValue: env.acl },
3114
3240
  {
3115
3241
  provide: ModalRegistryOptions, useValue: {
3116
3242
  modals: {
@@ -3158,5 +3284,5 @@ function flattenRoutes(routes, parentPath = '') {
3158
3284
  * Generated bundle index. Do not edit.
3159
3285
  */
3160
3286
 
3161
- export { AbstractMdService, AbstractSupportService, AppBreadcrumbService, AppContainerComponent, AppContextActions, AppContextActionsInternal, AppLoggerService, AppStorageService, AppTemplateComponent, AppsService, AsMultiPipe, AsSinglePipe, AuthActions, AuthActionsInternal, AuthFeatureService, AuthenticationService, AutolinkPipe, BaseComponent, CmsComponent, CmsPipe, ContentComponent, CookiesService, ErrorManagementService, ErrorModalComponent, KeycloakProfileService, LanguageService, LeftComponentPipe, LocalCacheService, ModalAppsComponent, NavbarActions, NavbarActionsInternal, OauthPasswordService, ParseJwtService, PwaUpdaterService, RLB_APPS, RLB_APP_NAVCOMP, RLB_CFG, RLB_CFG_AUTH, RLB_CFG_CMS, RLB_CFG_ENV, RLB_CFG_I18N, RLB_CFG_PAGES, RightComponentPipe, RlbAppModule, RlbRole, SidebarActions, SidebarActionsInternal, StrapiService, ToastComponent, TokenOauthInterceptor, TranslateBrowserLoader, TruncatePipe, UtilsService, appContextFeatureKey, authsFeatureKey, getDefaultRoutes, initialAppContextState, initialAuthState, initialNavbarState, initialSidebarState, navbarsFeatureKey, oauthGuard, oauthPasswordGuard, provideApp, provideRlbCodeBrowserOAuth, provideRlbConfig, provideRlbI18n, sidebarsFeatureKey, translateBrowserLoaderFactory, verifyDeactivate };
3287
+ export { AbstractMdService, AbstractSupportService, AclActions, AppBreadcrumbService, AppContainerComponent, AppContextActions, AppContextActionsInternal, AppLoggerService, AppStorageService, AppTemplateComponent, AppsService, AsMultiPipe, AsSinglePipe, AuthActions, AuthActionsInternal, AuthFeatureService, AuthenticationService, AutolinkPipe, BaseComponent, CmsComponent, CmsPipe, ContentComponent, CookiesService, ErrorManagementService, ErrorModalComponent, KeycloakProfileService, LanguageService, LeftComponentPipe, LocalCacheService, ModalAppsComponent, NavbarActions, NavbarActionsInternal, OauthPasswordService, ParseJwtService, PwaUpdaterService, RLB_APPS, RLB_APP_NAVCOMP, RLB_CFG, RLB_CFG_ACL, RLB_CFG_AUTH, RLB_CFG_CMS, RLB_CFG_ENV, RLB_CFG_I18N, RLB_CFG_PAGES, RightComponentPipe, RlbAppModule, RlbRole, SidebarActions, SidebarActionsInternal, StrapiService, ToastComponent, TokenOauthInterceptor, TranslateBrowserLoader, TruncatePipe, UtilsService, aclFeatureKey, appContextFeatureKey, authsFeatureKey, getDefaultRoutes, initialAclState, initialAppContextState, initialAuthState, initialNavbarState, initialSidebarState, navbarsFeatureKey, oauthGuard, oauthPasswordGuard, permissionGuard, provideApp, provideRlbCodeBrowserOAuth, provideRlbConfig, provideRlbI18n, sidebarsFeatureKey, translateBrowserLoaderFactory, verifyDeactivate };
3162
3288
  //# sourceMappingURL=open-rlb-ng-app.mjs.map