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