update auth & common ui modules
This commit is contained in:
parent
0a238622e7
commit
e007d5fe57
@ -63,14 +63,18 @@ export function keycloakInitializer(
|
||||
],
|
||||
})
|
||||
export class AuthModule extends ModuleWithOptions {
|
||||
static forRoot<I extends IIqserUser, C extends IqserUser & I, S extends BaseUserService<I, C>>(
|
||||
options: AuthModuleOptions<I, C, S>,
|
||||
): ModuleWithProviders<AuthModule> {
|
||||
static forRoot<
|
||||
Interface extends IIqserUser,
|
||||
Class extends IqserUser & Interface,
|
||||
UserService extends BaseUserService<Interface, Class>,
|
||||
RolesGuard extends RoleGuard = RoleGuard,
|
||||
>(options: AuthModuleOptions<Interface, Class, UserService, RolesGuard>): ModuleWithProviders<AuthModule> {
|
||||
const userService = this._getService(BaseUserService, DefaultUserService, options.existingUserService);
|
||||
const roleGuard = this._getService(RoleGuard, RoleGuard, options.existingRoleGuard);
|
||||
|
||||
return {
|
||||
ngModule: AuthModule,
|
||||
providers: [userService],
|
||||
providers: [userService, roleGuard],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ export abstract class BaseUserService<
|
||||
> extends EntitiesService<Interface, Class> {
|
||||
readonly currentUser$: Observable<Class | undefined>;
|
||||
protected abstract readonly _defaultModelPath: string;
|
||||
protected abstract readonly _rolesFilter: (role: string) => boolean;
|
||||
protected abstract readonly _entityClass: new (entityInterface: Interface | KeycloakProfile, ...args: unknown[]) => Class;
|
||||
protected readonly _currentUser$ = new BehaviorSubject<Class | undefined>(undefined);
|
||||
protected readonly _baseHref = inject(BASE_HREF);
|
||||
@ -60,13 +61,22 @@ export abstract class BaseUserService<
|
||||
);
|
||||
}
|
||||
|
||||
async loadCurrentUser(): Promise<Class> {
|
||||
async loadCurrentUser(): Promise<Class | undefined> {
|
||||
const token = await this._keycloakService.getToken();
|
||||
const decoded = jwt_decode(token);
|
||||
const userId = (<{ sub: string }>decoded).sub;
|
||||
|
||||
const roles = this._keycloakService.getUserRoles(true).filter(role => role.startsWith('RED_'));
|
||||
const user = new this._entityClass(await this._keycloakService.loadUserProfile(true), roles, userId);
|
||||
const roles = this._keycloakService.getUserRoles(true).filter(role => this._rolesFilter(role));
|
||||
let profile;
|
||||
try {
|
||||
profile = await this._keycloakService.loadUserProfile(true);
|
||||
} catch (e) {
|
||||
await this._keycloakService.logout();
|
||||
console.log(e);
|
||||
return;
|
||||
}
|
||||
|
||||
const user = new this._entityClass(profile, roles, userId);
|
||||
this.replace(user);
|
||||
|
||||
this._currentUser$.next(this.find(userId));
|
||||
@ -78,8 +88,8 @@ export abstract class BaseUserService<
|
||||
return this.find(userId)?.name;
|
||||
}
|
||||
|
||||
getAll(): Observable<Interface[]> {
|
||||
return super.getAll(this._defaultModelPath, [{ key: 'refreshCache', value: true }]);
|
||||
getAll(url = this._defaultModelPath): Observable<Interface[]> {
|
||||
return super.getAll(url, [{ key: 'refreshCache', value: true }]);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
@ -112,10 +122,14 @@ export abstract class BaseUserService<
|
||||
return new this._entityClass({ username: 'System' }, [], 'system');
|
||||
}
|
||||
|
||||
return super.find(id) || new this._entityClass({ username: 'Deleted User' }, [], 'deleted');
|
||||
if (!id) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return super.find(id) ?? new this._entityClass({ username: 'Deleted User' }, [], 'deleted');
|
||||
}
|
||||
}
|
||||
|
||||
export function getCurrentUser() {
|
||||
return inject(BaseUserService).currentUser;
|
||||
export function getCurrentUser<Class extends IqserUser = IqserUser>() {
|
||||
return inject<BaseUserService<IIqserUser, Class>>(BaseUserService).currentUser;
|
||||
}
|
||||
|
||||
@ -6,4 +6,5 @@ import { BaseUserService } from './base-user.service';
|
||||
export class DefaultUserService extends BaseUserService {
|
||||
protected readonly _defaultModelPath = 'user';
|
||||
protected readonly _entityClass = IqserUser;
|
||||
protected readonly _rolesFilter = () => true;
|
||||
}
|
||||
|
||||
@ -1,17 +1,15 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { LoadingService } from '../loading';
|
||||
import { BaseUserService } from './base-user.service';
|
||||
|
||||
@Injectable()
|
||||
export class RoleGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly _router: Router,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _userService: BaseUserService,
|
||||
) {}
|
||||
protected readonly _router = inject(Router);
|
||||
protected readonly _loadingService = inject(LoadingService);
|
||||
protected readonly _userService = inject(BaseUserService);
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
|
||||
const currentUser = this._userService.currentUser;
|
||||
if (!currentUser || !currentUser.hasAnyRole) {
|
||||
await this._router.navigate(['/auth-error']);
|
||||
|
||||
@ -2,7 +2,14 @@ import { BaseUserService } from '../base-user.service';
|
||||
import { IIqserUser } from './user.response';
|
||||
import { IqserUser } from '../user.model';
|
||||
import { Type } from '@angular/core';
|
||||
import { RoleGuard } from '../role.guard';
|
||||
|
||||
export interface AuthModuleOptions<I extends IIqserUser, C extends IqserUser & I, T extends BaseUserService<I, C> = BaseUserService<I, C>> {
|
||||
export interface AuthModuleOptions<
|
||||
I extends IIqserUser = IIqserUser,
|
||||
C extends IqserUser & I = IqserUser & I,
|
||||
T extends BaseUserService<I, C> = BaseUserService<I, C>,
|
||||
R extends RoleGuard = RoleGuard,
|
||||
> {
|
||||
existingUserService?: Type<T>;
|
||||
existingRoleGuard?: Type<R>;
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { SortByPipe } from './sorting';
|
||||
import { CapitalizePipe, HumanizePipe } from './utils';
|
||||
import { BaseAppConfig, CapitalizePipe, HumanizePipe } from './utils';
|
||||
import {
|
||||
HiddenActionComponent,
|
||||
LogoComponent,
|
||||
@ -27,7 +27,6 @@ import { IqserEmptyStatesModule } from './empty-states';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { KeycloakAngularModule } from 'keycloak-angular';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { UploadFileComponent } from './upload-file/upload-file.component';
|
||||
import { DragDropFileUploadDirective } from './upload-file/drag-drop-file-upload.directive';
|
||||
@ -40,7 +39,15 @@ import { BaseConfigService } from './services/base-config.service';
|
||||
import { DefaultUserPreferenceService } from './services/default-user-preference.service';
|
||||
import { ModuleWithOptions } from './utils/module-with-options';
|
||||
|
||||
const matModules = [MatIconModule, MatProgressSpinnerModule, MatButtonModule, MatDialogModule, MatCheckboxModule, MatTooltipModule];
|
||||
const matModules = [
|
||||
MatIconModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatButtonModule,
|
||||
MatDialogModule,
|
||||
MatCheckboxModule,
|
||||
MatTooltipModule,
|
||||
MatProgressBarModule,
|
||||
];
|
||||
const modules = [
|
||||
TranslateModule,
|
||||
IqserIconsModule,
|
||||
@ -73,13 +80,15 @@ const pipes = [SortByPipe, HumanizePipe, CapitalizePipe];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components, ...pipes],
|
||||
imports: [CommonModule, ...matModules, ...modules, FormsModule, ReactiveFormsModule, KeycloakAngularModule, MatProgressBarModule],
|
||||
imports: [CommonModule, ...matModules, ...modules, FormsModule, ReactiveFormsModule],
|
||||
exports: [...components, ...pipes, ...modules],
|
||||
})
|
||||
export class CommonUiModule extends ModuleWithOptions {
|
||||
static forRoot<T extends BaseUserPreferenceService, C extends BaseConfigService>(
|
||||
options: CommonUiOptions<T, C>,
|
||||
): ModuleWithProviders<CommonUiModule> {
|
||||
static forRoot<
|
||||
UserPreference extends BaseUserPreferenceService,
|
||||
Config extends BaseConfigService<AppConfig>,
|
||||
AppConfig extends BaseAppConfig = BaseAppConfig,
|
||||
>(options: CommonUiOptions<UserPreference, Config, AppConfig>): ModuleWithProviders<CommonUiModule> {
|
||||
const userPreferenceService = this._getService(
|
||||
BaseUserPreferenceService,
|
||||
DefaultUserPreferenceService,
|
||||
@ -91,9 +100,13 @@ export class CommonUiModule extends ModuleWithOptions {
|
||||
providers: [
|
||||
userPreferenceService,
|
||||
{
|
||||
provide: BaseConfigService,
|
||||
provide: options.configService,
|
||||
useFactory: options.configServiceFactory,
|
||||
},
|
||||
{
|
||||
provide: BaseConfigService,
|
||||
useExisting: options.configService,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ export class BaseConfigService<T extends BaseAppConfig = BaseAppConfig> {
|
||||
this._titleService.setTitle(this._values.APP_NAME);
|
||||
}
|
||||
|
||||
private _checkFrontendVersion(): void {
|
||||
protected _checkFrontendVersion(): void {
|
||||
this._cacheApiService.getCachedValue('FRONTEND_APP_VERSION').then(async lastVersion => {
|
||||
const version = this._values.FRONTEND_APP_VERSION;
|
||||
console.log('Last app version: ', lastVersion, ' current version ', version);
|
||||
|
||||
@ -1,7 +1,13 @@
|
||||
import { BaseConfigService, BaseUserPreferenceService } from '../../services';
|
||||
import { Type } from '@angular/core';
|
||||
import { BaseAppConfig } from '../base-app-config';
|
||||
|
||||
export interface CommonUiOptions<T extends BaseUserPreferenceService, C extends BaseConfigService> {
|
||||
existingUserPreferenceService?: Type<T>;
|
||||
configServiceFactory: () => C;
|
||||
export interface CommonUiOptions<
|
||||
UserPreference extends BaseUserPreferenceService,
|
||||
Config extends BaseConfigService<AppConfig>,
|
||||
AppConfig extends BaseAppConfig,
|
||||
> {
|
||||
existingUserPreferenceService?: Type<UserPreference>;
|
||||
configService: Type<Config>;
|
||||
configServiceFactory: () => Config;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user