diff --git a/src/app/core/guards/role.guard.ts b/src/app/core/guards/role.guard.ts index 16c23b8..271238f 100644 --- a/src/app/core/guards/role.guard.ts +++ b/src/app/core/guards/role.guard.ts @@ -6,7 +6,10 @@ import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular'; providedIn: 'root', }) export class RoleGuard extends KeycloakAuthGuard { - constructor(protected readonly router: Router, protected readonly keycloak: KeycloakService) { + constructor( + protected readonly router: Router, + protected readonly keycloak: KeycloakService, + ) { super(router, keycloak); } @@ -14,11 +17,11 @@ export class RoleGuard extends KeycloakAuthGuard { // Get the roles required from the route. const requiredRoles = route.data.expectedRole; - // Allow the user to to proceed if no additional roles are required to access the route. + // Allow the user to proceed if no additional roles are required to access the route. if (!(requiredRoles instanceof Array) || requiredRoles.length === 0) { return true; } - // Allow the user to proceed if all the required roles are present. - return requiredRoles.every((role) => this.roles.includes(role)); + // Allow the user to proceed if any the required roles are present. + return requiredRoles.some((role) => this.roles.includes(role)); } } diff --git a/src/app/core/models/settings.ts b/src/app/core/models/settings.ts index 2798321..b00ac47 100644 --- a/src/app/core/models/settings.ts +++ b/src/app/core/models/settings.ts @@ -11,4 +11,5 @@ export interface MenuLink { icon: IconProp; routerLink: any[]; numberOfTimesClicked?: number; + roles: string[]; } diff --git a/src/app/core/models/user.ts b/src/app/core/models/user.ts index 2c65d06..f14bb73 100644 --- a/src/app/core/models/user.ts +++ b/src/app/core/models/user.ts @@ -1,6 +1,6 @@ export interface User { - id: string; - email: string; + id?: string; + email?: string; username: string; authorities: string[]; } diff --git a/src/app/core/service/auth.service.ts b/src/app/core/service/auth.service.ts index 5991c93..23c715e 100644 --- a/src/app/core/service/auth.service.ts +++ b/src/app/core/service/auth.service.ts @@ -13,13 +13,16 @@ export class AuthService implements OnDestroy { keycloakSubscription: Subscription; loggedIn: EventEmitter = new EventEmitter(); tokenRefreshed: EventEmitter = new EventEmitter(); - constructor(private keycloakService: KeycloakService, private appInit: ApplicationInitStatus) { + constructor( + private keycloakService: KeycloakService, + private appInit: ApplicationInitStatus, + ) { this.appInit.donePromise.then(() => this.onInit()); } ngOnDestroy(): void { this.keycloakSubscription.unsubscribe(); } - onInit(): any { + async onInit() { this.keycloakSubscription = this.keycloakService.keycloakEvents$.subscribe(async (e) => { if ( e.type == KeycloakEventType.OnAuthError || @@ -57,6 +60,7 @@ export class AuthService implements OnDestroy { getUser(): User { return { + authorities: this.keycloakService.getUserRoles(), username: this.keycloakService.getUsername(), } as User; } diff --git a/src/app/core/service/notification.service.ts b/src/app/core/service/notification.service.ts index a900a6d..7f6f51e 100644 --- a/src/app/core/service/notification.service.ts +++ b/src/app/core/service/notification.service.ts @@ -1,5 +1,5 @@ import { HttpClient } from '@angular/common/http'; -import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; +import { Inject, Injectable, OnInit, PLATFORM_ID } from '@angular/core'; import { Observable, of, RetryConfig, Subscription, throwError, timer } from 'rxjs'; import { ArtcodedNotification } from '@core/models/artcoded.notification'; import { OnApplicationEvent } from '@core/interface/on-application-event'; @@ -8,6 +8,7 @@ import { AuthService } from '@core/service/auth.service'; import { Title } from '@angular/platform-browser'; import { isPlatformBrowser } from '@angular/common'; import { ConfigInitService } from '@init/config-init.service'; +import { PersonalInfoService } from './personal.info.service'; const GENERIC_RETRY_STRATEGY = () => { return { @@ -46,55 +47,62 @@ export class NotificationService { private titleService: Title, @Inject(PLATFORM_ID) private platformId: any, private configService: ConfigInitService, - private authService: AuthService - ) {} + private personalInfoService: PersonalInfoService, + private authService: AuthService, + ) { } latests(): Observable { return this.http.get( - `${this.configService.getConfig()['BACKEND_URL']}/api/notification?ngsw-bypass=true` + `${this.configService.getConfig()['BACKEND_URL']}/api/notification?ngsw-bypass=true`, ); } update(notificationId: string, seen: boolean): Observable { return this.http.post( `${this.configService.getConfig()['BACKEND_URL']}/api/notification?id=${notificationId}&seen=${seen}`, - {} + {}, ); } delete(notification: ArtcodedNotification): Observable { return this.http.delete( - `${this.configService.getConfig()['BACKEND_URL']}/api/notification?id=${notification.id}` + `${this.configService.getConfig()['BACKEND_URL']}/api/notification?id=${notification.id}`, ); } private startListening() { if (isPlatformBrowser(this.platformId)) { - console.log('start listening...'); - this.components = []; - this.pollingSub = timer(0, 5000) - .pipe( - switchMap((counter) => { - return this.latests(); - }), - retry(GENERIC_RETRY_STRATEGY()), - catchError((error) => of(error)) - ) - .subscribe((notifications) => { - this.updateTitle(notifications); - const newEvents = notifications?.filter((n) => !this.eventsAlreadySent.find((x) => x.id === n.id)); - this.components.forEach((component) => { - const componentEvents = newEvents.filter((evt) => component.shouldHandle(evt)); - if (componentEvents.length) { - component.handle(componentEvents); - if (component.shouldMarkEventAsSeenAfterConsumed()) { - this.markEventsAsSeen(componentEvents); - } - } - }); - this.eventsAlreadySent.push(...newEvents); - }); - this.loggedOutSubscription = this.authService.loggedOut.subscribe((o) => this.stopListening()); + this.personalInfoService.me().subscribe((user) => { + if (user.authorities.includes('ADMIN')) { + console.log('start listening...'); + this.components = []; + this.pollingSub = timer(0, 5000) + .pipe( + switchMap((_) => { + return this.latests(); + }), + retry(GENERIC_RETRY_STRATEGY()), + catchError((error) => of(error)), + ) + .subscribe((notifications) => { + this.updateTitle(notifications); + const newEvents = notifications?.filter((n) => !this.eventsAlreadySent.find((x) => x.id === n.id)); + this.components.forEach((component) => { + const componentEvents = newEvents.filter((evt) => component.shouldHandle(evt)); + if (componentEvents.length) { + component.handle(componentEvents); + if (component.shouldMarkEventAsSeenAfterConsumed()) { + this.markEventsAsSeen(componentEvents); + } + } + }); + this.eventsAlreadySent.push(...newEvents); + }); + this.loggedOutSubscription = this.authService.loggedOut.subscribe((_) => this.stopListening()); + } else { + console.log("user doesn't have admin role. do not listening to notifications"); + } + }); } } @@ -111,7 +119,7 @@ export class NotificationService { if (!this.pollingSub) { this.startListening(); } - this.components.push(onApplicationEvent); + this.components?.push(onApplicationEvent); } unsubscribe(onApplicationEvent: OnApplicationEvent): void { @@ -122,10 +130,10 @@ export class NotificationService { this.unseenCount = notifications?.filter((n) => !n.seen).length || 0; this.titleService.setTitle( (this.unseenCount === 0 ? '' : `(${this.unseenCount})`) + - this.titleService - .getTitle() - .replace(/\([\d]+\)/g, '') - .trim() + this.titleService + .getTitle() + .replace(/\([\d]+\)/g, '') + .trim(), ); } diff --git a/src/app/core/service/personal.info.service.ts b/src/app/core/service/personal.info.service.ts index 0cf25a9..3a37068 100644 --- a/src/app/core/service/personal.info.service.ts +++ b/src/app/core/service/personal.info.service.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { PersonalInfo } from '@core/models/personal.info'; import { ConfigInitService } from '@init/config-init.service'; +import { User } from '@core/models/user'; @Injectable({ providedIn: 'root', @@ -10,7 +11,10 @@ import { ConfigInitService } from '@init/config-init.service'; export class PersonalInfoService { basePath: string; - constructor(private http: HttpClient, private configService: ConfigInitService) { + constructor( + private http: HttpClient, + private configService: ConfigInitService, + ) { this.basePath = `${configService.getConfig()['BACKEND_URL']}/api/personal-info`; } @@ -18,6 +22,9 @@ export class PersonalInfoService { return this.http.get(this.basePath); } + public me(): Observable { + return this.http.get(this.basePath + '/@me'); + } public save(formData: FormData): Observable { return this.http.post(this.basePath + '/submit', formData); } diff --git a/src/app/features/administrative-document/file-upload-routing.module.ts b/src/app/features/administrative-document/administrative-document-routing.module.ts similarity index 81% rename from src/app/features/administrative-document/file-upload-routing.module.ts rename to src/app/features/administrative-document/administrative-document-routing.module.ts index 007a1fc..c2740fa 100644 --- a/src/app/features/administrative-document/file-upload-routing.module.ts +++ b/src/app/features/administrative-document/administrative-document-routing.module.ts @@ -9,7 +9,7 @@ const routes: Routes = [ path: '', component: DocumentResultComponent, canActivate: [AuthGuard, RoleGuard], - data: { expectedRole: ['ADMIN'] }, + data: { expectedRole: ['ADMIN', 'REGULATOR_OR_ACCOUNTANT'] }, }, ]; @@ -17,4 +17,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class AdministrativeDocumentRoutingModule {} +export class AdministrativeDocumentRoutingModule { } diff --git a/src/app/features/administrative-document/administrative-document.module.ts b/src/app/features/administrative-document/administrative-document.module.ts index c954c59..5bb13c7 100644 --- a/src/app/features/administrative-document/administrative-document.module.ts +++ b/src/app/features/administrative-document/administrative-document.module.ts @@ -5,7 +5,7 @@ import { SharedModule } from '@shared/shared.module'; import { NgbCollapseModule, NgbDropdownModule, NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; -import { AdministrativeDocumentRoutingModule } from '@feature/administrative-document/file-upload-routing.module'; +import { AdministrativeDocumentRoutingModule } from '@feature/administrative-document/administrative-document-routing.module'; import { DocumentEditorComponent } from './document-editor/document-editor.component'; import { AutosizeModule } from 'ngx-autosize'; import { NgxFileDropModule } from 'ngx-file-drop'; @@ -30,4 +30,4 @@ import { SplitPdfComponent } from './split-pdf/split-pdf.component'; NgbDropdownModule, ], }) -export class AdministrativeDocumentModule {} +export class AdministrativeDocumentModule { } diff --git a/src/app/features/billable-client/billable-client-routing.module.ts b/src/app/features/billable-client/billable-client-routing.module.ts index 0cd9f97..99278ea 100644 --- a/src/app/features/billable-client/billable-client-routing.module.ts +++ b/src/app/features/billable-client/billable-client-routing.module.ts @@ -9,7 +9,7 @@ const routes: Routes = [ path: '', component: BillableClientTableComponent, canActivate: [AuthGuard, RoleGuard], - data: { expectedRole: ['ADMIN'] }, + data: { expectedRole: ['ADMIN', 'REGULATOR_OR_ACCOUNTANT'] }, }, ]; @@ -17,4 +17,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class BillableClientRoutingModule {} +export class BillableClientRoutingModule { } diff --git a/src/app/features/dossier/dossier-routing.module.ts b/src/app/features/dossier/dossier-routing.module.ts index b16a979..fe47964 100644 --- a/src/app/features/dossier/dossier-routing.module.ts +++ b/src/app/features/dossier/dossier-routing.module.ts @@ -9,13 +9,13 @@ const routes: Routes = [ path: '', component: DossierPageComponent, canActivate: [AuthGuard, RoleGuard], - data: { expectedRole: ['ADMIN'] }, + data: { expectedRole: ['ADMIN', 'REGULATOR_OR_ACCOUNTANT'] }, }, { path: ':name', component: DossierPageComponent, canActivate: [AuthGuard, RoleGuard], - data: { expectedRole: ['ADMIN'] }, + data: { expectedRole: ['ADMIN', 'REGULATOR_OR_ACCOUNTANT'] }, }, ]; @@ -23,4 +23,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class DossierRoutingModule {} +export class DossierRoutingModule { } diff --git a/src/app/features/fee/fee-routing.module.ts b/src/app/features/fee/fee-routing.module.ts index b2763da..dd52b18 100644 --- a/src/app/features/fee/fee-routing.module.ts +++ b/src/app/features/fee/fee-routing.module.ts @@ -9,13 +9,13 @@ const routes: Routes = [ path: '', component: FeePageComponent, canActivate: [AuthGuard, RoleGuard], - data: { expectedRole: ['ADMIN'] }, + data: { expectedRole: ['ADMIN', 'REGULATOR_OR_ACCOUNTANT'] }, }, { path: ':name', component: FeePageComponent, canActivate: [AuthGuard, RoleGuard], - data: { expectedRole: ['ADMIN'] }, + data: { expectedRole: ['ADMIN', 'REGULATOR_OR_ACCOUNTANT'] }, }, ]; @@ -23,4 +23,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class FeeRoutingModule {} +export class FeeRoutingModule { } diff --git a/src/app/features/file-upload/file-upload-routing.module.ts b/src/app/features/file-upload/file-upload-routing.module.ts index ae6fd28..1be230d 100644 --- a/src/app/features/file-upload/file-upload-routing.module.ts +++ b/src/app/features/file-upload/file-upload-routing.module.ts @@ -9,7 +9,7 @@ const routes: Routes = [ path: '', component: FileUploadTableComponent, canActivate: [AuthGuard, RoleGuard], - data: { expectedRole: ['ADMIN'] }, + data: { expectedRole: ['ADMIN', 'REGULATOR_OR_ACCOUNTANT'] }, }, ]; @@ -17,4 +17,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class FileUploadRoutingModule {} +export class FileUploadRoutingModule { } diff --git a/src/app/features/invoice/invoice-routing.module.ts b/src/app/features/invoice/invoice-routing.module.ts index 4badcac..2e16e0b 100644 --- a/src/app/features/invoice/invoice-routing.module.ts +++ b/src/app/features/invoice/invoice-routing.module.ts @@ -9,13 +9,13 @@ const routes: Routes = [ path: '', component: InvoicePageComponent, canActivate: [AuthGuard, RoleGuard], - data: { expectedRole: ['ADMIN'] }, + data: { expectedRole: ['ADMIN', 'REGULATOR_OR_ACCOUNTANT'] }, }, { path: ':name', component: InvoicePageComponent, canActivate: [AuthGuard, RoleGuard], - data: { expectedRole: ['ADMIN'] }, + data: { expectedRole: ['ADMIN', 'REGULATOR_OR_ACCOUNTANT'] }, }, ]; @@ -23,4 +23,4 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], }) -export class InvoiceRoutingModule {} +export class InvoiceRoutingModule { } diff --git a/src/app/features/layout/navbar/navbar.component.html b/src/app/features/layout/navbar/navbar.component.html index d0fbe9d..0f989b9 100644 --- a/src/app/features/layout/navbar/navbar.component.html +++ b/src/app/features/layout/navbar/navbar.component.html @@ -26,14 +26,14 @@
- + - + - +
diff --git a/src/app/features/layout/navbar/navbar.component.ts b/src/app/features/layout/navbar/navbar.component.ts index fdb5d2d..285a0a8 100644 --- a/src/app/features/layout/navbar/navbar.component.ts +++ b/src/app/features/layout/navbar/navbar.component.ts @@ -12,6 +12,8 @@ import { Subscription, firstValueFrom } from 'rxjs'; import { environment } from '@env/environment'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { CacheComponent } from '../cache/cache.component'; +import { PersonalInfoService } from '@core/service/personal.info.service'; +import { User } from '@core/models/user'; @Component({ selector: 'app-navbar', templateUrl: './navbar.component.html', @@ -23,6 +25,7 @@ export class NavbarComponent implements OnInit, OnDestroy { env: any; navigationSubscriptions: Subscription[] = []; links: MenuLink[]; + user: User; link: MenuLink; version = environment.version; @@ -30,11 +33,12 @@ export class NavbarComponent implements OnInit, OnDestroy { constructor( @Inject(DOCUMENT) private document: Document, private configInitService: ConfigInitService, + private personalInfoService: PersonalInfoService, private settingsService: SettingsService, private modalService: NgbModal, private router: Router, private readonly updates: SwUpdate, - @Inject(PLATFORM_ID) private platformId: any + @Inject(PLATFORM_ID) private platformId: any, ) { } ngOnDestroy(): void { @@ -47,7 +51,7 @@ export class NavbarComponent implements OnInit, OnDestroy { } openCacheModal() { - this.modalService.open(CacheComponent, { size: "sm" }); + this.modalService.open(CacheComponent, { size: 'sm' }); } refreshPwa() { @@ -59,9 +63,13 @@ export class NavbarComponent implements OnInit, OnDestroy { this.navigationSubscriptions.forEach((n) => n.unsubscribe()); this.navigationSubscriptions = []; } + get hasRoleAdmin(): boolean { + return this.user.authorities.includes('ADMIN'); + } ngOnInit(): void { this.env = this.configInitService.getConfig()['ENV_TYPE']; this.links = FallbackMenu.getDefault().filter((l) => l.show); + this.navigationSubscriptions.push(this.personalInfoService.me().subscribe((u) => (this.user = u))); this.navigationSubscriptions.push( this.settingsService._menuLinks.subscribe( @@ -88,8 +96,8 @@ export class NavbarComponent implements OnInit, OnDestroy { }, (err) => { console.log(err, 'error loading menu links. fallback to default'); - } - ) + }, + ), ); } diff --git a/src/app/features/layout/sidebar/fallback-menu.ts b/src/app/features/layout/sidebar/fallback-menu.ts index 2fc9b38..848ab1d 100644 --- a/src/app/features/layout/sidebar/fallback-menu.ts +++ b/src/app/features/layout/sidebar/fallback-menu.ts @@ -16,6 +16,7 @@ export class FallbackMenu { routerLink: [''], show: true, numberOfTimesClicked: 0, + roles: ['REGULATOR_OR_ACCOUNTANT', 'ADMIN'], }, { id: '60083105215dd143d209d2cb', @@ -30,6 +31,7 @@ export class FallbackMenu { routerLink: ['tasks'], show: true, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2ca', @@ -44,6 +46,7 @@ export class FallbackMenu { routerLink: ['timesheets'], show: false, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2d5', @@ -58,6 +61,7 @@ export class FallbackMenu { routerLink: ['fee'], show: true, numberOfTimesClicked: 0, + roles: ['REGULATOR_OR_ACCOUNTANT', 'ADMIN'], }, { id: '60083105215dd143d209d2d3', @@ -72,6 +76,7 @@ export class FallbackMenu { routerLink: ['invoice'], show: true, numberOfTimesClicked: 0, + roles: ['REGULATOR_OR_ACCOUNTANT', 'ADMIN'], }, { id: '60083105215dd143d209d2d4', @@ -86,6 +91,7 @@ export class FallbackMenu { routerLink: ['dossier'], show: true, numberOfTimesClicked: 0, + roles: ['REGULATOR_OR_ACCOUNTANT', 'ADMIN'], }, { id: '60083105215dd143d209d2cc', @@ -100,6 +106,7 @@ export class FallbackMenu { routerLink: ['documents'], show: true, numberOfTimesClicked: 0, + roles: ['REGULATOR_OR_ACCOUNTANT', 'ADMIN'], }, { id: '60083105215dd143d209d2d1', @@ -114,6 +121,7 @@ export class FallbackMenu { routerLink: ['blog'], show: true, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2cf', @@ -128,6 +136,7 @@ export class FallbackMenu { routerLink: ['memzagram'], show: true, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2ce', @@ -142,6 +151,7 @@ export class FallbackMenu { routerLink: ['cv'], show: true, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2d6', @@ -156,6 +166,7 @@ export class FallbackMenu { routerLink: ['finance'], show: true, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2d8', @@ -170,6 +181,7 @@ export class FallbackMenu { routerLink: ['file-upload'], show: true, numberOfTimesClicked: 0, + roles: ['REGULATOR_OR_ACCOUNTANT', 'ADMIN'], }, { id: '60083105215dd193d209d3cd', @@ -184,6 +196,7 @@ export class FallbackMenu { routerLink: ['endpoint-sparql'], show: true, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { @@ -199,6 +212,7 @@ export class FallbackMenu { routerLink: ['toolbox', 'rdf'], show: true, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2da', @@ -213,6 +227,7 @@ export class FallbackMenu { routerLink: ['toolbox', 'date'], show: false, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2db', @@ -227,6 +242,7 @@ export class FallbackMenu { routerLink: ['toolbox', 'base64'], show: false, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2dc', @@ -241,6 +257,7 @@ export class FallbackMenu { routerLink: ['toolbox', 'pathfinder'], show: false, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: '60083105215dd143d209d2cd', @@ -255,6 +272,7 @@ export class FallbackMenu { routerLink: ['services'], show: true, numberOfTimesClicked: 0, + roles: ['ADMIN'], }, { id: 'a39533c8-1a63-4453-b407-deeb1b17bfc2', @@ -268,6 +286,7 @@ export class FallbackMenu { icon: ['fas', 'user'], routerLink: ['billable-clients'], show: true, + roles: ['REGULATOR_OR_ACCOUNTANT', 'ADMIN'], }, { id: '459d134a-6079-4309-8a33-70c53cf077fd', @@ -281,6 +300,7 @@ export class FallbackMenu { icon: ['fas', 'mail-bulk'], routerLink: ['mails'], show: true, + roles: ['ADMIN'], }, ]; } diff --git a/src/app/features/layout/user-menu/user-menu.component.html b/src/app/features/layout/user-menu/user-menu.component.html index 463d04e..bd0c632 100644 --- a/src/app/features/layout/user-menu/user-menu.component.html +++ b/src/app/features/layout/user-menu/user-menu.component.html @@ -1,7 +1,7 @@
- +
- -
diff --git a/src/app/features/layout/user-menu/user-menu.component.ts b/src/app/features/layout/user-menu/user-menu.component.ts index 41b7647..296838e 100644 --- a/src/app/features/layout/user-menu/user-menu.component.ts +++ b/src/app/features/layout/user-menu/user-menu.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { AuthService } from '@core/service/auth.service'; import { PersonalInfoService } from '@core/service/personal.info.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; @@ -10,6 +10,7 @@ import { firstValueFrom } from 'rxjs'; import { SmsFormComponent } from '@shared/sms-form/sms-form.component'; import { SmsService } from '@core/service/sms.service'; import { Sms } from '@core/models/sms'; +import { User } from '@core/models/user'; @Component({ selector: 'app-user-menu', @@ -18,14 +19,19 @@ import { Sms } from '@core/models/sms'; }) export class UserMenuComponent implements OnInit { frontOfficeUrl: string; + @Input() + user: User; + get hasRoleAdmin(): boolean { + return this.user.authorities.includes('ADMIN'); + } constructor( private personalInfoService: PersonalInfoService, private configService: ConfigInitService, private toastService: ToastService, private smsService: SmsService, private modalService: NgbModal, - private authenticationService: AuthService + private authenticationService: AuthService, ) { } ngOnInit(): void { @@ -40,7 +46,7 @@ export class UserMenuComponent implements OnInit { const personalInfo: PersonalInfo = await firstValueFrom(this.personalInfoService.get()); const modal = this.modalService.open(EditPersonalInfoComponent, { size: 'lg', - backdrop: 'static' + backdrop: 'static', }); modal.componentInstance.currentPersonalInfo = personalInfo; modal.componentInstance.onSavePersonalInfo.subscribe(async (formData: any) => { diff --git a/src/app/features/user-area/home/home.component.html b/src/app/features/user-area/home/home.component.html index 0b6568d..b676aaa 100644 --- a/src/app/features/user-area/home/home.component.html +++ b/src/app/features/user-area/home/home.component.html @@ -1,6 +1,6 @@
-
+
@@ -19,7 +19,7 @@
-
+
@@ -30,7 +30,7 @@
-
+
@@ -40,7 +40,7 @@
-
+
@@ -51,7 +51,7 @@
- +
@@ -73,10 +73,8 @@
-
+
diff --git a/src/app/features/user-area/home/home.component.ts b/src/app/features/user-area/home/home.component.ts index 448c9a0..b921431 100644 --- a/src/app/features/user-area/home/home.component.ts +++ b/src/app/features/user-area/home/home.component.ts @@ -4,9 +4,12 @@ import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core import { Title } from '@angular/platform-browser'; import { BackendInfo } from '@core/models/backend.info'; import { HealthIndicator } from '@core/models/health.indicator'; +import { User } from '@core/models/user'; +import { AuthService } from '@core/service/auth.service'; import { InfoService } from '@core/service/info.service'; +import { PersonalInfoService } from '@core/service/personal.info.service'; import { WindowRefService } from '@core/service/window.service'; -import { Observable, Subscription, combineLatest, map } from 'rxjs'; +import { Observable, Subscription, combineLatest, firstValueFrom, map } from 'rxjs'; type Indicators = { buildInfo: BackendInfo; healthIndicator: HealthIndicator }; @Component({ @@ -17,6 +20,7 @@ type Indicators = { buildInfo: BackendInfo; healthIndicator: HealthIndicator }; export class HomeComponent implements OnInit, OnDestroy { private subscription: Subscription; indicators$: Observable; + user: User; loaded: boolean = true; @@ -24,6 +28,7 @@ export class HomeComponent implements OnInit, OnDestroy { private titleService: Title, private breakPointObserver: BreakpointObserver, private infoService: InfoService, + private personalInfoService: PersonalInfoService, @Inject(PLATFORM_ID) private platformId: any, private windowService: WindowRefService, ) { } @@ -32,7 +37,12 @@ export class HomeComponent implements OnInit, OnDestroy { this.subscription?.unsubscribe(); } + get hasRoleAdmin(): boolean { + return this.user.authorities.includes('ADMIN'); + } async ngOnInit() { + this.user = await firstValueFrom(this.personalInfoService.me()); + if (isPlatformBrowser(this.platformId)) { // WORKAROUND bug plotly responsive this.subscription = this.breakPointObserver