mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-10-08 14:51:32 +00:00
[ci:force] - Fixed lint
This commit is contained in:
@@ -21,7 +21,6 @@ import { HttpParameterCodec } from '@angular/common/http';
|
||||
// does not encode some special characters like + with is causing issues with the alfresco js API and returns 500 error
|
||||
|
||||
export class AlfrescoApiParamEncoder implements HttpParameterCodec {
|
||||
|
||||
encodeKey(key: string): string {
|
||||
return encodeURIComponent(key);
|
||||
}
|
||||
|
@@ -16,10 +16,9 @@
|
||||
*/
|
||||
|
||||
export class AlfrescoApiResponseError extends Error {
|
||||
|
||||
public name = 'AlfrescoApiResponseError';
|
||||
|
||||
constructor(msg: string, public status: number, public response: Record<string, any> ) {
|
||||
constructor(msg: string, public status: number, public response: Record<string, any>) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@
|
||||
import { isConstructor, getQueryParamsWithCustomEncoder, removeNilValues } from './alfresco-api.utils';
|
||||
|
||||
describe('AlfrescoApiUtils', () => {
|
||||
|
||||
describe('isConstructor', () => {
|
||||
class MockClass {}
|
||||
/**
|
||||
@@ -50,9 +49,7 @@ describe('AlfrescoApiUtils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('getQueryParamsWithCustomEncoder', () => {
|
||||
|
||||
it('should return queryParams with removed undefined values', () => {
|
||||
const actual = getQueryParamsWithCustomEncoder({
|
||||
key1: 'value1',
|
||||
@@ -73,9 +70,7 @@ describe('AlfrescoApiUtils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('removeUndefinedValues', () => {
|
||||
|
||||
it('should return queryParams with removed undefined values', () => {
|
||||
const actual = removeNilValues({
|
||||
key1: 'value1',
|
||||
@@ -98,5 +93,4 @@ describe('AlfrescoApiUtils', () => {
|
||||
expect(actual?.getAll('key2')).toEqual(['value2', 'value3']);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -15,18 +15,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { HttpEvent, HttpUploadProgressEvent, HttpEventType, HttpResponse, HttpParams, HttpParameterCodec, HttpUrlEncodingCodec } from '@angular/common/http';
|
||||
import {
|
||||
HttpEvent,
|
||||
HttpUploadProgressEvent,
|
||||
HttpEventType,
|
||||
HttpResponse,
|
||||
HttpParams,
|
||||
HttpParameterCodec,
|
||||
HttpUrlEncodingCodec
|
||||
} from '@angular/common/http';
|
||||
import { Constructor } from '../types';
|
||||
|
||||
export const isHttpUploadProgressEvent = <T>(val: HttpEvent<T>): val is HttpUploadProgressEvent => val.type === HttpEventType.UploadProgress;
|
||||
export const isHttpResponseEvent = <T>(val: HttpEvent<T>): val is HttpResponse<T> => val.type === HttpEventType.Response;
|
||||
export const isDate = (value: unknown): value is Date => value instanceof Date;
|
||||
export const isXML = (value: unknown): boolean => typeof value === 'string' && value.startsWith('<?xml');
|
||||
export const isBlobResponse = (response: HttpResponse<any>, returnType: Constructor<unknown> | 'blob'): response is HttpResponse<Blob> => returnType === 'blob' || response.body instanceof Blob;
|
||||
export const isConstructor = <T = unknown>(value: any): value is Constructor<T> => typeof value === 'function' && !!value?.prototype?.constructor.name;
|
||||
export const isBlobResponse = (response: HttpResponse<any>, returnType: Constructor<unknown> | 'blob'): response is HttpResponse<Blob> =>
|
||||
returnType === 'blob' || response.body instanceof Blob;
|
||||
export const isConstructor = <T = unknown>(value: any): value is Constructor<T> =>
|
||||
typeof value === 'function' && !!value?.prototype?.constructor.name;
|
||||
|
||||
const convertParamsToString = (value: any): any => isDate(value) ? value.toISOString() : value;
|
||||
export const getQueryParamsWithCustomEncoder = (obj: Record<string | number, unknown>, encoder: HttpParameterCodec = new HttpUrlEncodingCodec()): HttpParams | undefined => {
|
||||
const convertParamsToString = (value: any): any => (isDate(value) ? value.toISOString() : value);
|
||||
export const getQueryParamsWithCustomEncoder = (
|
||||
obj: Record<string | number, unknown>,
|
||||
encoder: HttpParameterCodec = new HttpUrlEncodingCodec()
|
||||
): HttpParams | undefined => {
|
||||
if (!obj) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -38,7 +51,6 @@ export const getQueryParamsWithCustomEncoder = (obj: Record<string | number, unk
|
||||
const params = removeNilValues(obj);
|
||||
|
||||
for (const key in params) {
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(params, key)) {
|
||||
const value = params[key];
|
||||
if (value instanceof Array) {
|
||||
@@ -57,12 +69,10 @@ export const getQueryParamsWithCustomEncoder = (obj: Record<string | number, unk
|
||||
|
||||
/**
|
||||
* Removes null and undefined values from an object.
|
||||
*
|
||||
* @param obj object to process
|
||||
* @returns object with updated values
|
||||
*/
|
||||
export const removeNilValues = (obj: Record<string | number, unknown>) => {
|
||||
|
||||
if (!obj) {
|
||||
return {};
|
||||
}
|
||||
@@ -74,9 +84,7 @@ export const removeNilValues = (obj: Record<string | number, unknown>) => {
|
||||
}, {});
|
||||
};
|
||||
|
||||
|
||||
export const convertObjectToFormData = (formParams: Record<string | number, string | Blob>): FormData => {
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
for (const key in formParams) {
|
||||
|
@@ -17,6 +17,6 @@
|
||||
|
||||
export interface Dictionary<T> {
|
||||
[key: string]: T;
|
||||
};
|
||||
}
|
||||
|
||||
export type Constructor<T> = new (...args: any[]) => T;
|
||||
|
@@ -22,46 +22,47 @@ import { Authentication } from '../authentication';
|
||||
import { AuthenticationInterceptor, SHOULD_ADD_AUTH_TOKEN } from './authentication.interceptor';
|
||||
|
||||
class MockAuthentication extends Authentication {
|
||||
addTokenToHeader(_: string, httpHeaders: HttpHeaders): Observable<HttpHeaders> {
|
||||
return of(httpHeaders);
|
||||
}
|
||||
addTokenToHeader(_: string, httpHeaders: HttpHeaders): Observable<HttpHeaders> {
|
||||
return of(httpHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
const mockNext: HttpHandler = {
|
||||
handle: () => new Observable(subscriber => {
|
||||
subscriber.complete();
|
||||
})
|
||||
handle: () =>
|
||||
new Observable((subscriber) => {
|
||||
subscriber.complete();
|
||||
})
|
||||
};
|
||||
|
||||
const request = new HttpRequest('GET', 'http://localhost:4200');
|
||||
|
||||
describe('AuthenticationInterceptor', () => {
|
||||
let interceptor: AuthenticationInterceptor;
|
||||
let addTokenToHeaderSpy: jasmine.Spy<any>;
|
||||
let interceptor: AuthenticationInterceptor;
|
||||
let addTokenToHeaderSpy: jasmine.Spy<any>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [AuthenticationInterceptor, {provide: Authentication, useClass: MockAuthentication}]
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [AuthenticationInterceptor, { provide: Authentication, useClass: MockAuthentication }]
|
||||
});
|
||||
interceptor = TestBed.inject(AuthenticationInterceptor);
|
||||
addTokenToHeaderSpy = spyOn(interceptor['authService'], 'addTokenToHeader');
|
||||
});
|
||||
interceptor = TestBed.inject(AuthenticationInterceptor);
|
||||
addTokenToHeaderSpy = spyOn(interceptor['authService'], 'addTokenToHeader');
|
||||
});
|
||||
|
||||
it('should call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to true', () => {
|
||||
addTokenToHeaderSpy.and.callThrough();
|
||||
request.context.set(SHOULD_ADD_AUTH_TOKEN, true);
|
||||
interceptor.intercept(request, mockNext);
|
||||
expect(addTokenToHeaderSpy).toHaveBeenCalled();
|
||||
});
|
||||
it('should call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to true', () => {
|
||||
addTokenToHeaderSpy.and.callThrough();
|
||||
request.context.set(SHOULD_ADD_AUTH_TOKEN, true);
|
||||
interceptor.intercept(request, mockNext);
|
||||
expect(addTokenToHeaderSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to false', () => {
|
||||
request.context.set(SHOULD_ADD_AUTH_TOKEN, false);
|
||||
interceptor.intercept(request, mockNext);
|
||||
expect(addTokenToHeaderSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to false', () => {
|
||||
request.context.set(SHOULD_ADD_AUTH_TOKEN, false);
|
||||
interceptor.intercept(request, mockNext);
|
||||
expect(addTokenToHeaderSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is not provided', () => {
|
||||
interceptor.intercept(request, mockNext);
|
||||
expect(addTokenToHeaderSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is not provided', () => {
|
||||
interceptor.intercept(request, mockNext);
|
||||
expect(addTokenToHeaderSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@@ -36,42 +36,37 @@ export const SHOULD_ADD_AUTH_TOKEN = new HttpContextToken<boolean>(() => false);
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationInterceptor implements HttpInterceptor {
|
||||
constructor(private authService: Authentication) {}
|
||||
|
||||
constructor( private authService: Authentication) { }
|
||||
intercept(
|
||||
req: HttpRequest<any>,
|
||||
next: HttpHandler
|
||||
): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
|
||||
if (req.context.get(SHOULD_ADD_AUTH_TOKEN)) {
|
||||
return this.authService.addTokenToHeader(req.url, req.headers).pipe(
|
||||
mergeMap((headersWithBearer) => {
|
||||
const headerWithContentType = this.appendJsonContentType(headersWithBearer);
|
||||
const kcReq = req.clone({ headers: headerWithContentType });
|
||||
return next.handle(kcReq).pipe(catchError((error) => observableThrowError(error)));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler):
|
||||
Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
|
||||
|
||||
if (req.context.get(SHOULD_ADD_AUTH_TOKEN)) {
|
||||
return this.authService.addTokenToHeader(req.url, req.headers).pipe(
|
||||
mergeMap((headersWithBearer) => {
|
||||
const headerWithContentType = this.appendJsonContentType(headersWithBearer);
|
||||
const kcReq = req.clone({ headers: headerWithContentType});
|
||||
return next.handle(kcReq)
|
||||
.pipe(
|
||||
catchError((error) => observableThrowError(error))
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return next.handle(req).pipe(catchError((error) => observableThrowError(error)));
|
||||
return next.handle(req).pipe(catchError((error) => observableThrowError(error)));
|
||||
}
|
||||
|
||||
private appendJsonContentType(headers: HttpHeaders): HttpHeaders {
|
||||
// prevent adding any content type, to properly handle formData with boundary browser generated value,
|
||||
// as adding any Content-Type its going to break the upload functionality
|
||||
|
||||
// prevent adding any content type, to properly handle formData with boundary browser generated value,
|
||||
// as adding any Content-Type its going to break the upload functionality
|
||||
if (headers.get('Content-Type') === 'multipart/form-data') {
|
||||
return headers.delete('Content-Type');
|
||||
}
|
||||
|
||||
if (headers.get('Content-Type') === 'multipart/form-data') {
|
||||
return headers.delete('Content-Type');
|
||||
}
|
||||
if (!headers.get('Content-Type')) {
|
||||
return headers.set('Content-Type', 'application/json;charset=UTF-8');
|
||||
}
|
||||
|
||||
if (!headers.get('Content-Type')) {
|
||||
return headers.set('Content-Type', 'application/json;charset=UTF-8');
|
||||
}
|
||||
|
||||
return headers;
|
||||
return headers;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -32,7 +32,6 @@ type StoryWithoutFunction<T> = NonFunctionProperties<StoryFn<T>>;
|
||||
|
||||
/**
|
||||
* Copy storybook story
|
||||
*
|
||||
* @param story story
|
||||
* @param annotations annotations
|
||||
* @returns a copy of the story
|
||||
@@ -47,13 +46,7 @@ const meta: Meta = {
|
||||
component: DemoBreadcrumbComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [
|
||||
BreadcrumbComponent,
|
||||
BreadcrumbItemComponent,
|
||||
MatButtonModule,
|
||||
MatMenuModule,
|
||||
MatIconModule
|
||||
]
|
||||
imports: [BreadcrumbComponent, BreadcrumbItemComponent, MatButtonModule, MatMenuModule, MatIconModule]
|
||||
}),
|
||||
applicationConfig({
|
||||
providers: [importProvidersFrom(CoreStoryModule)]
|
||||
|
@@ -15,11 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-demo-breadcrumb',
|
||||
template: `
|
||||
selector: 'adf-demo-breadcrumb',
|
||||
template: `
|
||||
<adf-breadcrumb [compact]="compact">
|
||||
<adf-breadcrumb-item>
|
||||
<a href="/">Home</a>
|
||||
@@ -58,6 +58,6 @@ import {Component} from '@angular/core';
|
||||
`
|
||||
})
|
||||
export class DemoBreadcrumbComponent {
|
||||
compact = false;
|
||||
showBreadcrumbItemWithMenu = false;
|
||||
compact = false;
|
||||
showBreadcrumbItemWithMenu = false;
|
||||
}
|
||||
|
@@ -34,13 +34,8 @@ export class BreadcrumbFocusDirective {
|
||||
|
||||
private getFocusableElements(root: HTMLElement): HTMLElement[] {
|
||||
const allFocusableElements = `button, a, input, select, textarea, [tabindex]:not([tabindex="-1"])`;
|
||||
return Array.from(
|
||||
root.querySelectorAll(
|
||||
allFocusableElements
|
||||
) as NodeListOf<HTMLElement>
|
||||
).filter(
|
||||
(element) =>
|
||||
!element.hasAttribute('disabled') && element.tabIndex >= 0
|
||||
return Array.from(root.querySelectorAll(allFocusableElements) as NodeListOf<HTMLElement>).filter(
|
||||
(element) => !element.hasAttribute('disabled') && element.tabIndex >= 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ import { Observable } from 'rxjs';
|
||||
export const isFeatureOff = (flag: string) => () => inject(FeaturesServiceToken).isOff$(flag);
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class IsFeatureOff {
|
||||
export class IsFeatureOff {
|
||||
constructor(@Inject(FeaturesServiceToken) private featuresServiceToken: IFeaturesService) {}
|
||||
|
||||
canMatch(route: Route): Observable<boolean> {
|
||||
|
@@ -23,7 +23,7 @@ import { Observable } from 'rxjs';
|
||||
export const isFeatureOn = (flag: string) => () => inject(FeaturesServiceToken).isOn$(flag);
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class IsFeatureOn {
|
||||
export class IsFeatureOn {
|
||||
constructor(@Inject(FeaturesServiceToken) private featuresServiceToken: IFeaturesService) {}
|
||||
|
||||
canMatch(route: Route): Observable<boolean> {
|
||||
|
@@ -18,11 +18,10 @@
|
||||
import { Inject, Injectable, Optional, inject } from '@angular/core';
|
||||
import { FlagsOverrideToken } from '../interfaces/features.interface';
|
||||
|
||||
|
||||
export const isFlagsOverrideOn = () => () => inject(FlagsOverrideToken) ?? false;
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class IsFlagsOverrideOn {
|
||||
export class IsFlagsOverrideOn {
|
||||
constructor(@Optional() @Inject(FlagsOverrideToken) private devToolsToken: boolean) {}
|
||||
|
||||
canMatch(): boolean {
|
||||
|
@@ -23,7 +23,6 @@ import { DummyFeaturesService } from '../services/dummy-features.service';
|
||||
|
||||
/**
|
||||
* Provides the dummy feature flags.
|
||||
*
|
||||
* @returns Environment Providers for Feature Flags.
|
||||
*/
|
||||
export function provideDummyFeatureFlags() {
|
||||
|
@@ -68,7 +68,6 @@ export class DebugFeaturesService implements IDebugFeaturesService {
|
||||
|
||||
/**
|
||||
* Gets the flags as an observable.
|
||||
*
|
||||
* @returns the observable that emits the flag changeset.
|
||||
*/
|
||||
getFlags$(): Observable<FlagChangeset> {
|
||||
@@ -79,7 +78,6 @@ export class DebugFeaturesService implements IDebugFeaturesService {
|
||||
|
||||
/**
|
||||
* Resets the specified flags.
|
||||
*
|
||||
* @param flags The flags to reset.
|
||||
*/
|
||||
resetFlags(flags: FlagSet): void {
|
||||
|
@@ -41,7 +41,6 @@ export class ShellModule {
|
||||
|
||||
/**
|
||||
* Resolve module for routes
|
||||
*
|
||||
* @param routes route configuration
|
||||
* @returns module with providers
|
||||
*/
|
||||
@@ -60,7 +59,6 @@ function getModuleForRoutes(routes: Routes): ModuleWithProviders<ShellModule> {
|
||||
|
||||
/**
|
||||
* Resolve a module for the route configuration
|
||||
*
|
||||
* @param config route configuration
|
||||
* @returns module with providers
|
||||
*/
|
||||
|
@@ -20,8 +20,8 @@ import { ShellLayoutComponent } from './components/shell/shell.component';
|
||||
import { SHELL_AUTH_TOKEN } from './services/shell-app.service';
|
||||
|
||||
export const SHELL_LAYOUT_ROUTE: Route = {
|
||||
path: '',
|
||||
component: ShellLayoutComponent,
|
||||
canActivate: [SHELL_AUTH_TOKEN],
|
||||
children: []
|
||||
path: '',
|
||||
component: ShellLayoutComponent,
|
||||
canActivate: [SHELL_AUTH_TOKEN],
|
||||
children: []
|
||||
};
|
||||
|
@@ -69,10 +69,7 @@ describe('StoragePrefixFactory', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const prefixFactory = new StoragePrefixFactory(
|
||||
appConfigService as AppConfigService,
|
||||
externalPrefixFactory
|
||||
);
|
||||
const prefixFactory = new StoragePrefixFactory(appConfigService as AppConfigService, externalPrefixFactory);
|
||||
|
||||
prefixFactory.getPrefix().subscribe((prefix) => {
|
||||
expect(prefix).toBe('prefix-from-factory');
|
||||
@@ -95,10 +92,7 @@ describe('StoragePrefixFactory', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const prefixFactory = new StoragePrefixFactory(
|
||||
appConfigService as AppConfigService,
|
||||
externalPrefixFactory
|
||||
);
|
||||
const prefixFactory = new StoragePrefixFactory(appConfigService as AppConfigService, externalPrefixFactory);
|
||||
|
||||
prefixFactory.getPrefix().subscribe((prefix) => {
|
||||
expect(prefix).toBe(appConfigPrefix);
|
||||
|
@@ -33,7 +33,8 @@ export class StoragePrefixFactory {
|
||||
constructor(
|
||||
private appConfigService: AppConfigService,
|
||||
@Optional()
|
||||
@Inject(STORAGE_PREFIX_FACTORY_SERVICE) private storagePrefixFactory?: StoragePrefixFactoryService
|
||||
@Inject(STORAGE_PREFIX_FACTORY_SERVICE)
|
||||
private storagePrefixFactory?: StoragePrefixFactoryService
|
||||
) {}
|
||||
|
||||
getPrefix(): Observable<string | undefined> {
|
||||
@@ -43,9 +44,7 @@ export class StoragePrefixFactory {
|
||||
return of(prefix);
|
||||
}
|
||||
|
||||
return this.storagePrefixFactory ?
|
||||
this.storagePrefixFactory.getPrefix() :
|
||||
of(prefix);
|
||||
return this.storagePrefixFactory ? this.storagePrefixFactory.getPrefix() : of(prefix);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@@ -22,7 +22,6 @@ import { StoragePrefixFactory } from './app-config-storage-prefix.factory';
|
||||
|
||||
/**
|
||||
* Create a factory to load app configuration
|
||||
*
|
||||
* @param appConfigService app config service
|
||||
* @param storageService storage service
|
||||
* @param adfHttpClient http client
|
||||
@@ -34,8 +33,7 @@ export function loadAppConfig(
|
||||
storageService: StorageService,
|
||||
adfHttpClient: AdfHttpClient,
|
||||
storagePrefixFactory: StoragePrefixFactory
|
||||
) {
|
||||
|
||||
) {
|
||||
const init = () => {
|
||||
adfHttpClient.disableCsrf = appConfigService.get<boolean>(AppConfigValues.DISABLECSRF, true);
|
||||
storageService.prefix = appConfigService.get<string>(AppConfigValues.STORAGE_PREFIX, '');
|
||||
@@ -45,4 +43,4 @@ export function loadAppConfig(
|
||||
});
|
||||
};
|
||||
return () => appConfigService.load(init);
|
||||
};
|
||||
}
|
||||
|
@@ -95,7 +95,6 @@ export class AppConfigService {
|
||||
|
||||
/**
|
||||
* Requests notification of a property value when it is loaded.
|
||||
*
|
||||
* @param property The desired property value
|
||||
* @returns Property value, when loaded
|
||||
*/
|
||||
@@ -108,7 +107,6 @@ export class AppConfigService {
|
||||
|
||||
/**
|
||||
* Gets the value of a named property.
|
||||
*
|
||||
* @param key Name of the property
|
||||
* @param defaultValue Value to return if the key is not found
|
||||
* @returns Value of the property
|
||||
@@ -139,7 +137,6 @@ export class AppConfigService {
|
||||
|
||||
/**
|
||||
* Gets the location.protocol value.
|
||||
*
|
||||
* @returns The location.protocol string
|
||||
*/
|
||||
getLocationProtocol(): string {
|
||||
@@ -148,7 +145,6 @@ export class AppConfigService {
|
||||
|
||||
/**
|
||||
* Gets the location.hostname property.
|
||||
*
|
||||
* @returns Value of the property
|
||||
*/
|
||||
getLocationHostname(): string {
|
||||
@@ -157,7 +153,6 @@ export class AppConfigService {
|
||||
|
||||
/**
|
||||
* Gets the location.port property.
|
||||
*
|
||||
* @param prefix Text added before port value
|
||||
* @returns Port with prefix
|
||||
*/
|
||||
@@ -187,7 +182,6 @@ export class AppConfigService {
|
||||
|
||||
/**
|
||||
* Loads the config file.
|
||||
*
|
||||
* @param callback an optional callback to execute when configuration is loaded
|
||||
* @returns Notification when loading is complete
|
||||
*/
|
||||
@@ -223,7 +217,6 @@ export class AppConfigService {
|
||||
|
||||
/**
|
||||
* Call the discovery API to fetch configuration
|
||||
*
|
||||
* @param hostIdp host address
|
||||
* @returns Discovery configuration
|
||||
*/
|
||||
@@ -244,7 +237,6 @@ export class AppConfigService {
|
||||
|
||||
/**
|
||||
* OAuth2 configuration
|
||||
*
|
||||
* @returns auth config model
|
||||
*/
|
||||
get oauth2(): OauthConfigModel {
|
||||
|
@@ -23,9 +23,10 @@ import { AuthenticationService } from '../services/authentication.service';
|
||||
import { RedirectAuthService } from '../oidc/redirect-auth.service';
|
||||
|
||||
const mockNext: HttpHandler = {
|
||||
handle: () => new Observable(subscriber => {
|
||||
subscriber.complete();
|
||||
})
|
||||
handle: () =>
|
||||
new Observable((subscriber) => {
|
||||
subscriber.complete();
|
||||
})
|
||||
};
|
||||
|
||||
const mockRequest = (url) => new HttpRequest('GET', url);
|
||||
|
@@ -18,8 +18,15 @@
|
||||
import { throwError as observableThrowError, Observable } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
HttpHandler, HttpInterceptor, HttpRequest,
|
||||
HttpSentEvent, HttpHeaderResponse, HttpProgressEvent, HttpResponse, HttpUserEvent, HttpHeaders
|
||||
HttpHandler,
|
||||
HttpInterceptor,
|
||||
HttpRequest,
|
||||
HttpSentEvent,
|
||||
HttpHeaderResponse,
|
||||
HttpProgressEvent,
|
||||
HttpResponse,
|
||||
HttpUserEvent,
|
||||
HttpHeaders
|
||||
} from '@angular/common/http';
|
||||
import { catchError, mergeMap } from 'rxjs/operators';
|
||||
import { AuthenticationService } from '../services/authentication.service';
|
||||
@@ -30,61 +37,52 @@ export class AuthBearerInterceptor implements HttpInterceptor {
|
||||
|
||||
private excludedUrlsRegex: RegExp[];
|
||||
|
||||
constructor(private authenticationService: AuthenticationService) { }
|
||||
constructor(private authenticationService: AuthenticationService) {}
|
||||
|
||||
private loadExcludedUrlsRegex() {
|
||||
const excludedUrls = this.bearerExcludedUrls;
|
||||
this.excludedUrlsRegex = excludedUrls.map((urlPattern) => new RegExp(`^https?://[^/]+/${urlPattern}`, 'i')) || [];
|
||||
}
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler):
|
||||
Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
|
||||
|
||||
|
||||
if (!this.excludedUrlsRegex) {
|
||||
this.loadExcludedUrlsRegex();
|
||||
private loadExcludedUrlsRegex() {
|
||||
const excludedUrls = this.bearerExcludedUrls;
|
||||
this.excludedUrlsRegex = excludedUrls.map((urlPattern) => new RegExp(`^https?://[^/]+/${urlPattern}`, 'i')) || [];
|
||||
}
|
||||
|
||||
const requestUrl = req.url;
|
||||
const shallPass: boolean = this.excludedUrlsRegex.some((regex) => regex.test(requestUrl));
|
||||
if (shallPass) {
|
||||
return next.handle(req)
|
||||
.pipe(
|
||||
catchError((error) => observableThrowError(error))
|
||||
intercept(
|
||||
req: HttpRequest<any>,
|
||||
next: HttpHandler
|
||||
): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
|
||||
if (!this.excludedUrlsRegex) {
|
||||
this.loadExcludedUrlsRegex();
|
||||
}
|
||||
|
||||
const requestUrl = req.url;
|
||||
const shallPass: boolean = this.excludedUrlsRegex.some((regex) => regex.test(requestUrl));
|
||||
if (shallPass) {
|
||||
return next.handle(req).pipe(catchError((error) => observableThrowError(error)));
|
||||
}
|
||||
|
||||
return this.authenticationService.addTokenToHeader(requestUrl, req.headers).pipe(
|
||||
mergeMap((headersWithBearer) => {
|
||||
const headerWithContentType = this.appendJsonContentType(headersWithBearer, req.body);
|
||||
const kcReq = req.clone({ headers: headerWithContentType });
|
||||
return next.handle(kcReq).pipe(catchError((error) => observableThrowError(error)));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return this.authenticationService.addTokenToHeader(requestUrl, req.headers)
|
||||
.pipe(
|
||||
mergeMap((headersWithBearer) => {
|
||||
const headerWithContentType = this.appendJsonContentType(headersWithBearer, req.body);
|
||||
const kcReq = req.clone({ headers: headerWithContentType});
|
||||
return next.handle(kcReq)
|
||||
.pipe(
|
||||
catchError((error) => observableThrowError(error))
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
private appendJsonContentType(headers: HttpHeaders, reqBody: any): HttpHeaders {
|
||||
// prevent adding any content type, to properly handle formData with boundary browser generated value,
|
||||
// as adding any Content-Type its going to break the upload functionality
|
||||
|
||||
private appendJsonContentType(headers: HttpHeaders, reqBody: any): HttpHeaders {
|
||||
if (headers.get('Content-Type') === 'multipart/form-data' && !(reqBody instanceof FormData)) {
|
||||
return headers.delete('Content-Type');
|
||||
}
|
||||
|
||||
// prevent adding any content type, to properly handle formData with boundary browser generated value,
|
||||
// as adding any Content-Type its going to break the upload functionality
|
||||
if (!headers.get('Content-Type') && !(reqBody instanceof FormData)) {
|
||||
return headers.set('Content-Type', 'application/json;charset=UTF-8');
|
||||
}
|
||||
|
||||
if (headers.get('Content-Type') === 'multipart/form-data' && !(reqBody instanceof FormData)) {
|
||||
return headers.delete('Content-Type');
|
||||
return headers;
|
||||
}
|
||||
|
||||
if (!headers.get('Content-Type') && !(reqBody instanceof FormData)) {
|
||||
return headers.set('Content-Type', 'application/json;charset=UTF-8');
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
protected get bearerExcludedUrls(): readonly string[] {
|
||||
return this._bearerExcludedUrls;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -38,7 +38,6 @@ export interface TicketEntry {
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ContentAuth {
|
||||
|
||||
onLogin = new ReplaySubject<any>(1);
|
||||
onLogout = new ReplaySubject<any>(1);
|
||||
onError = new Subject<any>();
|
||||
@@ -60,9 +59,7 @@ export class ContentAuth {
|
||||
return this.appConfigService.get<string>(AppConfigValues.ECMHOST) + '/' + contextRootEcm + '/api/-default-/public/authentication/versions/1';
|
||||
}
|
||||
|
||||
constructor(private appConfigService: AppConfigService,
|
||||
private adfHttpClient: AdfHttpClient,
|
||||
private storageService: StorageService) {
|
||||
constructor(private appConfigService: AppConfigService, private adfHttpClient: AdfHttpClient, private storageService: StorageService) {
|
||||
this.appConfigService.onLoad.subscribe(() => {
|
||||
this.setConfig();
|
||||
});
|
||||
@@ -72,7 +69,6 @@ export class ContentAuth {
|
||||
if (this.storageService.getItem(AppConfigValues.CONTENT_TICKET_STORAGE_LABEL)) {
|
||||
this.setTicket(this.storageService.getItem(AppConfigValues.CONTENT_TICKET_STORAGE_LABEL));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
saveUsername(username: string) {
|
||||
@@ -85,7 +81,6 @@ export class ContentAuth {
|
||||
|
||||
/**
|
||||
* login Alfresco API
|
||||
*
|
||||
* @param username username to login
|
||||
* @param password password to login
|
||||
* @returns A promise that returns {new authentication ticket} if resolved and {error} if rejected.
|
||||
@@ -127,7 +122,6 @@ export class ContentAuth {
|
||||
|
||||
/**
|
||||
* logout Alfresco API
|
||||
*
|
||||
* @returns A promise that returns { authentication ticket} if resolved and {error} if rejected.
|
||||
*/
|
||||
logout(): Promise<any> {
|
||||
@@ -148,13 +142,13 @@ export class ContentAuth {
|
||||
this.adfHttpClient.emit('error');
|
||||
this.onError.next('error');
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current Ticket
|
||||
*
|
||||
* @param ticket a string representing the ticket
|
||||
*/
|
||||
setTicket(ticket: string) {
|
||||
@@ -200,12 +194,12 @@ export class ContentAuth {
|
||||
|
||||
createTicket(ticketBodyCreate: TicketBody): Promise<TicketEntry> {
|
||||
if (ticketBodyCreate === null || ticketBodyCreate === undefined) {
|
||||
this.onError.next((`Missing param ticketBodyCreate`));
|
||||
this.onError.next(`Missing param ticketBodyCreate`);
|
||||
|
||||
throw new Error(`Missing param ticketBodyCreate`);
|
||||
}
|
||||
|
||||
return this.adfHttpClient.post(this.basePath + '/tickets', {bodyParam: ticketBodyCreate});
|
||||
return this.adfHttpClient.post(this.basePath + '/tickets', { bodyParam: ticketBodyCreate });
|
||||
}
|
||||
|
||||
async requireAlfTicket(): Promise<void> {
|
||||
@@ -216,5 +210,4 @@ export class ContentAuth {
|
||||
deleteTicket(): Promise<any> {
|
||||
return this.adfHttpClient.delete(this.basePath + '/tickets/-me-');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -22,12 +22,10 @@ import { AppConfigService, AppConfigValues } from '../../app-config/app-config.s
|
||||
import { StorageService } from '../../common/services/storage.service';
|
||||
import { ReplaySubject, Subject } from 'rxjs';
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ProcessAuth {
|
||||
|
||||
onLogin = new ReplaySubject<any>(1);
|
||||
onLogout = new ReplaySubject<any>(1);
|
||||
onError = new Subject<any>();
|
||||
@@ -38,7 +36,8 @@ export class ProcessAuth {
|
||||
};
|
||||
|
||||
authentications: Authentication = {
|
||||
basicAuth: {ticket: ''}, type: 'activiti'
|
||||
basicAuth: { ticket: '' },
|
||||
type: 'activiti'
|
||||
};
|
||||
|
||||
get basePath(): string {
|
||||
@@ -46,9 +45,7 @@ export class ProcessAuth {
|
||||
return this.appConfigService.get<string>(AppConfigValues.BPMHOST) + '/' + contextRootBpm;
|
||||
}
|
||||
|
||||
constructor(private appConfigService: AppConfigService,
|
||||
private adfHttpClient: AdfHttpClient,
|
||||
private storageService: StorageService) {
|
||||
constructor(private appConfigService: AppConfigService, private adfHttpClient: AdfHttpClient, private storageService: StorageService) {
|
||||
this.appConfigService.onLoad.subscribe(() => {
|
||||
this.setConfig();
|
||||
});
|
||||
@@ -70,7 +67,6 @@ export class ProcessAuth {
|
||||
|
||||
/**
|
||||
* login Activiti API
|
||||
*
|
||||
* @param username Username to login
|
||||
* @param password Password to login
|
||||
* @returns A promise that returns {new authentication ticket} if resolved and {error} if rejected.
|
||||
@@ -118,7 +114,8 @@ export class ProcessAuth {
|
||||
this.onError.next('error');
|
||||
}
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
return promise;
|
||||
@@ -126,7 +123,6 @@ export class ProcessAuth {
|
||||
|
||||
/**
|
||||
* logout Alfresco API
|
||||
*
|
||||
* @returns A promise that returns {new authentication ticket} if resolved and {error} if rejected.
|
||||
*/
|
||||
async logout(): Promise<any> {
|
||||
@@ -147,7 +143,8 @@ export class ProcessAuth {
|
||||
this.adfHttpClient.emit('error');
|
||||
this.onError.next('error');
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -167,7 +164,6 @@ export class ProcessAuth {
|
||||
|
||||
/**
|
||||
* Set the current Ticket
|
||||
*
|
||||
* @param ticket a string representing the ticket
|
||||
*/
|
||||
setTicket(ticket: string) {
|
||||
|
@@ -39,7 +39,6 @@ describe('Auth Guard SSO role service', () => {
|
||||
|
||||
/**
|
||||
* Spy on user access
|
||||
*
|
||||
* @param realmRoles roles
|
||||
* @param resourceAccess resource access values
|
||||
*/
|
||||
|
@@ -48,7 +48,7 @@ export const AuthGuardSsoRoleService: CanActivateFn = (route: ActivatedRouteSnap
|
||||
}
|
||||
const hasRole = hasRealmRole && hasClientRole;
|
||||
|
||||
if (!hasRole && route?.data && route.data['redirectUrl']) {
|
||||
if (!hasRole && route?.data?.['redirectUrl']) {
|
||||
const router = inject(Router);
|
||||
router.navigate(['/' + route.data['redirectUrl']]);
|
||||
}
|
||||
|
@@ -20,39 +20,53 @@ import { IdentityRoleModel } from '../models/identity-role.model';
|
||||
import { IdentityJoinGroupRequestModel } from '../interfaces/identity-user.service.interface';
|
||||
|
||||
export const mockIdentityGroup1 = {
|
||||
id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: []
|
||||
id: 'mock-group-id-1',
|
||||
name: 'Mock Group 1',
|
||||
path: '/mock',
|
||||
subGroups: []
|
||||
} as IdentityGroupModel;
|
||||
|
||||
export const mockIdentityGroup2 = {
|
||||
id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: []
|
||||
id: 'mock-group-id-2',
|
||||
name: 'Mock Group 2',
|
||||
path: '',
|
||||
subGroups: []
|
||||
} as IdentityGroupModel;
|
||||
|
||||
export const mockIdentityGroup3 = {
|
||||
id: 'mock-group-id-3', name: 'Mock Group 3', path: '', subGroups: []
|
||||
id: 'mock-group-id-3',
|
||||
name: 'Mock Group 3',
|
||||
path: '',
|
||||
subGroups: []
|
||||
} as IdentityGroupModel;
|
||||
|
||||
export const mockIdentityGroup4 = {
|
||||
id: 'mock-group-id-4', name: 'Mock Group 4', path: '', subGroups: []
|
||||
id: 'mock-group-id-4',
|
||||
name: 'Mock Group 4',
|
||||
path: '',
|
||||
subGroups: []
|
||||
} as IdentityGroupModel;
|
||||
|
||||
export const mockIdentityGroup5 = {
|
||||
id: 'mock-group-id-5', name: 'Mock Group 5', path: '', subGroups: []
|
||||
id: 'mock-group-id-5',
|
||||
name: 'Mock Group 5',
|
||||
path: '',
|
||||
subGroups: []
|
||||
} as IdentityGroupModel;
|
||||
|
||||
export const mockIdentityGroupsCount = { count: 10 } as IdentityGroupCountModel;
|
||||
|
||||
export const mockIdentityGroups = [
|
||||
mockIdentityGroup1, mockIdentityGroup2, mockIdentityGroup3, mockIdentityGroup4, mockIdentityGroup5
|
||||
];
|
||||
export const mockIdentityGroups = [mockIdentityGroup1, mockIdentityGroup2, mockIdentityGroup3, mockIdentityGroup4, mockIdentityGroup5];
|
||||
|
||||
export const roleMappingMock = [
|
||||
{ id: 'role-id-1', name: 'role-name-1' }, { id: 'role-id-2', name: 'role-name-2' }
|
||||
{ id: 'role-id-1', name: 'role-name-1' },
|
||||
{ id: 'role-id-2', name: 'role-name-2' }
|
||||
];
|
||||
|
||||
export const mockIdentityRoles = [
|
||||
new IdentityRoleModel({id: 'mock-role-id', name: 'MOCK-ADMIN-ROLE'}),
|
||||
new IdentityRoleModel({id: 'mock-role-id', name: 'MOCK-USER-ROLE'}),
|
||||
new IdentityRoleModel({id: 'mock-role-id', name: 'MOCK-ROLE-1'})
|
||||
new IdentityRoleModel({ id: 'mock-role-id', name: 'MOCK-ADMIN-ROLE' }),
|
||||
new IdentityRoleModel({ id: 'mock-role-id', name: 'MOCK-USER-ROLE' }),
|
||||
new IdentityRoleModel({ id: 'mock-role-id', name: 'MOCK-ROLE-1' })
|
||||
];
|
||||
|
||||
export const clientRoles: IdentityRoleModel[] = [
|
||||
@@ -60,14 +74,20 @@ export const clientRoles: IdentityRoleModel[] = [
|
||||
new IdentityRoleModel({ name: 'MOCK-USER-ROLE' })
|
||||
];
|
||||
|
||||
export const mockJoinGroupRequest: IdentityJoinGroupRequestModel = {userId: 'mock-hser-id', groupId: 'mock-group-id', realm: 'mock-realm-name'};
|
||||
export const mockJoinGroupRequest: IdentityJoinGroupRequestModel = { userId: 'mock-hser-id', groupId: 'mock-group-id', realm: 'mock-realm-name' };
|
||||
|
||||
export const mockGroup1 = {
|
||||
id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: []
|
||||
id: 'mock-group-id-1',
|
||||
name: 'Mock Group 1',
|
||||
path: '/mock',
|
||||
subGroups: []
|
||||
} as IdentityGroupModel;
|
||||
|
||||
export const mockGroup2 = {
|
||||
id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: []
|
||||
id: 'mock-group-id-2',
|
||||
name: 'Mock Group 2',
|
||||
path: '',
|
||||
subGroups: []
|
||||
} as IdentityGroupModel;
|
||||
|
||||
export const mockGroups = [
|
||||
|
@@ -31,7 +31,6 @@ import { IdentityRoleModel } from '../models/identity-role.model';
|
||||
|
||||
Injectable({ providedIn: 'root' });
|
||||
export class IdentityGroupServiceMock implements IdentityGroupServiceInterface {
|
||||
|
||||
getGroups(): Observable<IdentityGroupModel[]> {
|
||||
return of(mockIdentityGroups);
|
||||
}
|
||||
@@ -81,9 +80,7 @@ export class IdentityGroupServiceMock implements IdentityGroupServiceInterface {
|
||||
return of([]);
|
||||
}
|
||||
|
||||
return of(mockIdentityGroups.filter(group =>
|
||||
group.name.toUpperCase().includes(searchParams.name.toUpperCase())
|
||||
));
|
||||
return of(mockIdentityGroups.filter((group) => group.name.toUpperCase().includes(searchParams.name.toUpperCase())));
|
||||
}
|
||||
|
||||
getGroupRoles(_groupId: string): Observable<IdentityRoleModel[]> {
|
||||
@@ -91,19 +88,21 @@ export class IdentityGroupServiceMock implements IdentityGroupServiceInterface {
|
||||
}
|
||||
|
||||
checkGroupHasRole(groupId: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getGroupRoles(groupId).pipe(map((groupRoles) => {
|
||||
let hasRole = false;
|
||||
if (groupRoles?.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = groupRoles.find(({ name }) => roleName === name);
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
}));
|
||||
return this.getGroupRoles(groupId).pipe(
|
||||
map((groupRoles) => {
|
||||
let hasRole = false;
|
||||
if (groupRoles?.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = groupRoles.find(({ name }) => roleName === name);
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getClientIdByApplicationName(_applicationName: string): Observable<string> {
|
||||
@@ -119,9 +118,7 @@ export class IdentityGroupServiceMock implements IdentityGroupServiceInterface {
|
||||
}
|
||||
|
||||
checkGroupHasClientApp(groupId: string, clientId: string): Observable<boolean> {
|
||||
return this.getClientRoles(groupId, clientId).pipe(
|
||||
map((response) => response && response.length > 0)
|
||||
);
|
||||
return this.getClientRoles(groupId, clientId).pipe(map((response) => response && response.length > 0));
|
||||
}
|
||||
|
||||
checkGroupHasAnyClientAppRole(groupId: string, clientId: string, roleNames: string[]): Observable<boolean> {
|
||||
|
@@ -18,37 +18,61 @@
|
||||
import { IdentityUserModel } from '../models/identity-user.model';
|
||||
import { IdentityRoleModel } from '../models/identity-role.model';
|
||||
|
||||
export const mockIdentityUser1: IdentityUserModel = { id: 'mock-user-id-1', username: 'userName1', firstName: 'first-name-1', lastName: 'last-name-1', email: 'abc@xyz.com' };
|
||||
export const mockIdentityUser2: IdentityUserModel = { id: 'mock-user-id-2', username: 'userName2', firstName: 'first-name-2', lastName: 'last-name-2', email: 'abcd@xyz.com'};
|
||||
export const mockIdentityUser3: IdentityUserModel = { id: 'mock-user-id-3', username: 'userName3', firstName: 'first-name-3', lastName: 'last-name-3', email: 'abcde@xyz.com' };
|
||||
export const mockIdentityUser4: IdentityUserModel = { id: 'mock-user-id-4', username: 'userName4', firstName: 'first-name-4', lastName: 'last-name-4', email: 'abcde@xyz.com' };
|
||||
export const mockIdentityUser5: IdentityUserModel = { id: 'mock-user-id-5', username: 'userName5', firstName: 'first-name-5', lastName: 'last-name-5', email: 'abcde@xyz.com' };
|
||||
export const mockIdentityUser1: IdentityUserModel = {
|
||||
id: 'mock-user-id-1',
|
||||
username: 'userName1',
|
||||
firstName: 'first-name-1',
|
||||
lastName: 'last-name-1',
|
||||
email: 'abc@xyz.com'
|
||||
};
|
||||
export const mockIdentityUser2: IdentityUserModel = {
|
||||
id: 'mock-user-id-2',
|
||||
username: 'userName2',
|
||||
firstName: 'first-name-2',
|
||||
lastName: 'last-name-2',
|
||||
email: 'abcd@xyz.com'
|
||||
};
|
||||
export const mockIdentityUser3: IdentityUserModel = {
|
||||
id: 'mock-user-id-3',
|
||||
username: 'userName3',
|
||||
firstName: 'first-name-3',
|
||||
lastName: 'last-name-3',
|
||||
email: 'abcde@xyz.com'
|
||||
};
|
||||
export const mockIdentityUser4: IdentityUserModel = {
|
||||
id: 'mock-user-id-4',
|
||||
username: 'userName4',
|
||||
firstName: 'first-name-4',
|
||||
lastName: 'last-name-4',
|
||||
email: 'abcde@xyz.com'
|
||||
};
|
||||
export const mockIdentityUser5: IdentityUserModel = {
|
||||
id: 'mock-user-id-5',
|
||||
username: 'userName5',
|
||||
firstName: 'first-name-5',
|
||||
lastName: 'last-name-5',
|
||||
email: 'abcde@xyz.com'
|
||||
};
|
||||
|
||||
export const mockIdentityUsers: IdentityUserModel[] = [
|
||||
mockIdentityUser1,
|
||||
mockIdentityUser2,
|
||||
mockIdentityUser3,
|
||||
mockIdentityUser4,
|
||||
mockIdentityUser5
|
||||
];
|
||||
export const mockIdentityUsers: IdentityUserModel[] = [mockIdentityUser1, mockIdentityUser2, mockIdentityUser3, mockIdentityUser4, mockIdentityUser5];
|
||||
|
||||
export const mockIdentityRole = new IdentityRoleModel({ id: 'id-1', name: 'MOCK-ADMIN-ROLE'});
|
||||
export const mockIdentityRole = new IdentityRoleModel({ id: 'id-1', name: 'MOCK-ADMIN-ROLE' });
|
||||
|
||||
export const mockAvailableRoles = [
|
||||
new IdentityRoleModel({ id: 'mock-role-id-1', name: 'MOCK-ADMIN-ROLE'}),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-2', name: 'MOCK-USER-ROLE'}),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-1', name: 'MOCK-ADMIN-ROLE' }),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-2', name: 'MOCK-USER-ROLE' }),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-3', name: 'MOCK_MODELER-ROLE' }),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-5', name: 'MOCK-ROLE-2'})
|
||||
new IdentityRoleModel({ id: 'mock-role-id-5', name: 'MOCK-ROLE-2' })
|
||||
];
|
||||
|
||||
export const mockAssignedRoles = [
|
||||
new IdentityRoleModel({ id: 'mock-role-id-1', name: 'MOCK-ADMIN-ROLE'}),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-1', name: 'MOCK-ADMIN-ROLE' }),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-2', name: 'MOCK_MODELER-ROLE' }),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-3', name: 'MOCK-ROLE-1' })
|
||||
];
|
||||
|
||||
export const mockEffectiveRoles = [
|
||||
new IdentityRoleModel({id: 'mock-role-id-1', name: 'MOCK-ACTIVE-ADMIN-ROLE'}),
|
||||
new IdentityRoleModel({id: 'mock-role-id-2', name: 'MOCK-ACTIVE-USER-ROLE'}),
|
||||
new IdentityRoleModel({id: 'mock-role-id-3', name: 'MOCK-ROLE-1'})
|
||||
new IdentityRoleModel({ id: 'mock-role-id-1', name: 'MOCK-ACTIVE-ADMIN-ROLE' }),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-2', name: 'MOCK-ACTIVE-USER-ROLE' }),
|
||||
new IdentityRoleModel({ id: 'mock-role-id-3', name: 'MOCK-ROLE-1' })
|
||||
];
|
||||
|
@@ -35,7 +35,6 @@ import { mockAssignedRoles, mockAvailableRoles, mockEffectiveRoles, mockIdentity
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class IdentityUserServiceMock implements IdentityUserServiceInterface {
|
||||
|
||||
getCurrentUserInfo(): IdentityUserModel {
|
||||
return mockIdentityUser1;
|
||||
}
|
||||
@@ -45,9 +44,7 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
|
||||
return of([]);
|
||||
}
|
||||
|
||||
return of(mockIdentityUsers.filter(user =>
|
||||
user.username.toUpperCase().includes(search.toUpperCase())
|
||||
));
|
||||
return of(mockIdentityUsers.filter((user) => user.username.toUpperCase().includes(search.toUpperCase())));
|
||||
}
|
||||
|
||||
findUserByUsername(username: string): Observable<IdentityUserModel[]> {
|
||||
@@ -55,7 +52,7 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
|
||||
return of([]);
|
||||
}
|
||||
|
||||
return of(mockIdentityUsers.filter(user => user.username === username));
|
||||
return of(mockIdentityUsers.filter((user) => user.username === username));
|
||||
}
|
||||
|
||||
findUserByEmail(email: string): Observable<IdentityUserModel[]> {
|
||||
@@ -63,7 +60,7 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
|
||||
return of([]);
|
||||
}
|
||||
|
||||
return of(mockIdentityUsers.filter(user => user.email === email));
|
||||
return of(mockIdentityUsers.filter((user) => user.email === email));
|
||||
}
|
||||
|
||||
findUserById(id: string): Observable<any> {
|
||||
@@ -71,7 +68,7 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
|
||||
return of([]);
|
||||
}
|
||||
|
||||
return of(mockIdentityUsers.find(user => user.id === id));
|
||||
return of(mockIdentityUsers.find((user) => user.id === id));
|
||||
}
|
||||
|
||||
getClientRoles(userId: string, _clientId: string): Observable<any[]> {
|
||||
@@ -83,9 +80,7 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
|
||||
}
|
||||
|
||||
checkUserHasClientApp(userId: string, clientId: string): Observable<boolean> {
|
||||
return this.getClientRoles(userId, clientId).pipe(
|
||||
map((clientRoles) => clientRoles.length > 0)
|
||||
);
|
||||
return this.getClientRoles(userId, clientId).pipe(map((clientRoles) => clientRoles.length > 0));
|
||||
}
|
||||
|
||||
checkUserHasAnyClientAppRole(userId: string, clientId: string, roleNames: string[]): Observable<boolean> {
|
||||
@@ -112,9 +107,7 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
|
||||
}
|
||||
|
||||
checkUserHasApplicationAccess(userId: string, applicationName: string): Observable<boolean> {
|
||||
return this.getClientIdByApplicationName(applicationName).pipe(
|
||||
switchMap((clientId: string) => this.checkUserHasClientApp(userId, clientId))
|
||||
);
|
||||
return this.getClientIdByApplicationName(applicationName).pipe(switchMap((clientId: string) => this.checkUserHasClientApp(userId, clientId)));
|
||||
}
|
||||
|
||||
checkUserHasAnyApplicationRole(userId: string, applicationName: string, roleNames: string[]): Observable<boolean> {
|
||||
@@ -178,19 +171,21 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
|
||||
}
|
||||
|
||||
checkUserHasRole(userId: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getUserRoles(userId).pipe(map((userRoles: IdentityRoleModel[]) => {
|
||||
let hasRole = false;
|
||||
if (userRoles && userRoles.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = userRoles.find(({ name }) => roleName === name);
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
}));
|
||||
return this.getUserRoles(userId).pipe(
|
||||
map((userRoles: IdentityRoleModel[]) => {
|
||||
let hasRole = false;
|
||||
if (userRoles && userRoles.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = userRoles.find(({ name }) => roleName === name);
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
queryUsers(_requestQuery: IdentityUserQueryCloudRequestModel): Observable<IdentityUserQueryResponse> {
|
||||
|
@@ -128,6 +128,6 @@ export const deleteGroupMappingApi: any = {
|
||||
|
||||
export const applicationDetailsMockApi: any = {
|
||||
oauth2Auth: {
|
||||
callCustomApi: () => Promise.resolve([{id: 'mock-app-id', name: 'mock-app-name'}])
|
||||
callCustomApi: () => Promise.resolve([{ id: 'mock-app-id', name: 'mock-app-name' }])
|
||||
}
|
||||
};
|
||||
|
@@ -29,5 +29,4 @@ export class RedirectionModel {
|
||||
this.url = obj.url || null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -24,7 +24,6 @@ import { OauthConfigModel } from '../models/oauth-config.model';
|
||||
|
||||
/**
|
||||
* Create auth configuration factory
|
||||
*
|
||||
* @param authConfigService auth config service
|
||||
* @returns factory function
|
||||
*/
|
||||
|
@@ -15,27 +15,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { APP_INITIALIZER, inject, ModuleWithProviders, NgModule, InjectionToken } from '@angular/core';
|
||||
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { AUTH_CONFIG, OAuthModule, OAuthStorage } from 'angular-oauth2-oidc';
|
||||
import { AuthenticationService } from '../services/authentication.service';
|
||||
import { StorageService } from '../../common/services/storage.service';
|
||||
import { AuthModuleConfig, AUTH_MODULE_CONFIG } from './auth-config';
|
||||
import { authConfigFactory, AuthConfigService } from './auth-config.service';
|
||||
import { AuthRoutingModule } from './auth-routing.module';
|
||||
import { AuthService } from './auth.service';
|
||||
import { RedirectAuthService } from './redirect-auth.service';
|
||||
import { AuthenticationConfirmationComponent } from './view/authentication-confirmation/authentication-confirmation.component';
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { TokenInterceptor } from './token.interceptor';
|
||||
import { StorageService } from '../../common/services/storage.service';
|
||||
|
||||
export const JWT_STORAGE_SERVICE = new InjectionToken<OAuthStorage>('JWT_STORAGE_SERVICE', {
|
||||
providedIn: 'root',
|
||||
factory: () => inject(StorageService)
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a Login Factory function
|
||||
*
|
||||
* @param redirectService auth redirect service
|
||||
* @returns a factory function
|
||||
*/
|
||||
@@ -43,18 +35,11 @@ export function loginFactory(redirectService: RedirectAuthService): () => Promis
|
||||
return () => redirectService.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns current instance of OAuthStorage
|
||||
*/
|
||||
export function oauthStorageFactory(): OAuthStorage {
|
||||
return inject(JWT_STORAGE_SERVICE);
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [AuthenticationConfirmationComponent],
|
||||
imports: [AuthRoutingModule, OAuthModule.forRoot()],
|
||||
providers: [
|
||||
{ provide: OAuthStorage, useFactory: oauthStorageFactory },
|
||||
{ provide: OAuthStorage, useExisting: StorageService },
|
||||
{ provide: AuthenticationService },
|
||||
{
|
||||
provide: AUTH_CONFIG,
|
||||
@@ -68,11 +53,6 @@ export function oauthStorageFactory(): OAuthStorage {
|
||||
useFactory: loginFactory,
|
||||
deps: [RedirectAuthService],
|
||||
multi: true
|
||||
},
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: TokenInterceptor,
|
||||
multi: true
|
||||
}
|
||||
]
|
||||
})
|
||||
|
@@ -485,5 +485,4 @@ describe('RedirectAuthService', () => {
|
||||
|
||||
expect(expectedLogoutIsEmitted).toBeTrue();
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -18,9 +18,9 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
template: '<div data-automation-id="auth-confirmation"></div>',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
template: '<div data-automation-id="auth-confirmation"></div>',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AuthenticationConfirmationComponent {
|
||||
constructor(){}
|
||||
constructor() {}
|
||||
}
|
||||
|
@@ -35,9 +35,7 @@ export class AuthenticationService implements AuthenticationServiceInterface, ee
|
||||
constructor(private injector: Injector, private redirectAuthService: RedirectAuthService) {
|
||||
this.redirectAuthService.onLogin.subscribe((value) => this.onLogin.next(value));
|
||||
|
||||
this.redirectAuthService.onTokenReceived.subscribe(
|
||||
(value) => this.onTokenReceived.next(value)
|
||||
);
|
||||
this.redirectAuthService.onTokenReceived.subscribe((value) => this.onTokenReceived.next(value));
|
||||
|
||||
this.basicAlfrescoAuthService.onLogin.subscribe((value) => this.onLogin.next(value));
|
||||
|
||||
|
@@ -59,7 +59,6 @@ export abstract class BaseAuthenticationService implements AuthenticationService
|
||||
|
||||
/**
|
||||
* Adds the auth token to an HTTP header using the 'bearer' scheme.
|
||||
*
|
||||
* @param requestUrl the request url
|
||||
* @param headersArg Header that will receive the token
|
||||
* @returns The new header with the token added
|
||||
@@ -88,7 +87,6 @@ export abstract class BaseAuthenticationService implements AuthenticationService
|
||||
|
||||
/**
|
||||
* Does the provider support BPM?
|
||||
*
|
||||
* @returns True if supported, false otherwise
|
||||
*/
|
||||
isBPMProvider(): boolean {
|
||||
@@ -102,7 +100,6 @@ export abstract class BaseAuthenticationService implements AuthenticationService
|
||||
|
||||
/**
|
||||
* Does the provider support both ECM and BPM?
|
||||
*
|
||||
* @returns True if both are supported, false otherwise
|
||||
*/
|
||||
isALLProvider(): boolean {
|
||||
@@ -117,7 +114,6 @@ export abstract class BaseAuthenticationService implements AuthenticationService
|
||||
|
||||
/**
|
||||
* Prints an error message in the console browser
|
||||
*
|
||||
* @param error Error message
|
||||
* @returns Object representing the error message
|
||||
*/
|
||||
|
@@ -32,11 +32,7 @@ import { OAuth2Service } from './oauth2.service';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
constructor(
|
||||
private oAuth2Service: OAuth2Service,
|
||||
private appConfigService: AppConfigService
|
||||
) {}
|
||||
constructor(private oAuth2Service: OAuth2Service, private appConfigService: AppConfigService) {}
|
||||
|
||||
private get identityHost(): string {
|
||||
return `${this.appConfigService.get('identityHost')}`;
|
||||
@@ -44,7 +40,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets all groups.
|
||||
*
|
||||
* @returns Array of group information objects
|
||||
*/
|
||||
getGroups(): Observable<IdentityGroupModel[]> {
|
||||
@@ -54,7 +49,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets available roles
|
||||
*
|
||||
* @param groupId Id of the group.
|
||||
* @returns Array of available roles information objects
|
||||
*/
|
||||
@@ -65,7 +59,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets assigned roles
|
||||
*
|
||||
* @param groupId Id of the group.
|
||||
* @returns Array of available roles
|
||||
*/
|
||||
@@ -76,7 +69,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Assigns roles to the group
|
||||
*
|
||||
* @param groupId The ID of the group
|
||||
* @param roles Array of roles to assign
|
||||
* @returns request result
|
||||
@@ -90,7 +82,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Removes roles from the group
|
||||
*
|
||||
* @param groupId The ID of the group
|
||||
* @param roles Array of roles to remove
|
||||
* @returns request result
|
||||
@@ -104,7 +95,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Get effective roles
|
||||
*
|
||||
* @param groupId Id of the group
|
||||
* @returns Array of effective roles
|
||||
*/
|
||||
@@ -115,7 +105,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Queries groups.
|
||||
*
|
||||
* @param requestQuery query settings
|
||||
* @returns Array of user information objects
|
||||
*/
|
||||
@@ -125,24 +114,27 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
return this.getTotalGroupsCount().pipe(
|
||||
switchMap((totalCount: IdentityGroupCountModel) =>
|
||||
this.oAuth2Service.get<any[]>({ url, queryParams }).pipe(
|
||||
map((response) => ({
|
||||
entries: response,
|
||||
pagination: {
|
||||
skipCount: requestQuery.first,
|
||||
maxItems: requestQuery.max,
|
||||
count: totalCount.count,
|
||||
hasMoreItems: false,
|
||||
totalItems: totalCount.count
|
||||
}
|
||||
} as IdentityGroupQueryResponse))
|
||||
))
|
||||
this.oAuth2Service.get<any[]>({ url, queryParams }).pipe(
|
||||
map(
|
||||
(response) =>
|
||||
({
|
||||
entries: response,
|
||||
pagination: {
|
||||
skipCount: requestQuery.first,
|
||||
maxItems: requestQuery.max,
|
||||
count: totalCount.count,
|
||||
hasMoreItems: false,
|
||||
totalItems: totalCount.count
|
||||
}
|
||||
} as IdentityGroupQueryResponse)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets groups total count.
|
||||
*
|
||||
* @returns Number of groups count.
|
||||
*/
|
||||
getTotalGroupsCount(): Observable<IdentityGroupCountModel> {
|
||||
@@ -152,7 +144,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Creates new group.
|
||||
*
|
||||
* @param newGroup Object of containing the new group details.
|
||||
* @returns Empty response when the group created.
|
||||
*/
|
||||
@@ -165,7 +156,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Updates group details.
|
||||
*
|
||||
* @param groupId Id of the targeted group.
|
||||
* @param updatedGroup Object of containing the group details
|
||||
* @returns Empty response when the group updated.
|
||||
@@ -179,7 +169,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Deletes Group.
|
||||
*
|
||||
* @param groupId Id of the group.
|
||||
* @returns Empty response when the group deleted.
|
||||
*/
|
||||
@@ -190,7 +179,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Finds groups filtered by name.
|
||||
*
|
||||
* @param searchParams Object containing the name filter string
|
||||
* @returns List of group information
|
||||
*/
|
||||
@@ -206,7 +194,6 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets details for a specified group.
|
||||
*
|
||||
* @param groupId Id of the target group
|
||||
* @returns Group details
|
||||
*/
|
||||
@@ -217,45 +204,42 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Check that a group has one or more roles from the supplied list.
|
||||
*
|
||||
* @param groupId Id of the target group
|
||||
* @param roleNames Array of role names
|
||||
* @returns True if the group has one or more of the roles, false otherwise
|
||||
*/
|
||||
checkGroupHasRole(groupId: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getGroupRoles(groupId).pipe(map((groupRoles) => {
|
||||
let hasRole = false;
|
||||
if (groupRoles?.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = groupRoles.find(({ name }) => roleName === name);
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
}));
|
||||
checkGroupHasRole(groupId: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getGroupRoles(groupId).pipe(
|
||||
map((groupRoles) => {
|
||||
let hasRole = false;
|
||||
if (groupRoles?.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = groupRoles.find(({ name }) => roleName === name);
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client Id using the app name.
|
||||
*
|
||||
* @param applicationName Name of the app
|
||||
* @returns client Id string
|
||||
*/
|
||||
getClientIdByApplicationName(applicationName: string): Observable<string> {
|
||||
const url = `${this.identityHost}/clients`;
|
||||
const queryParams = {clientId: applicationName};
|
||||
const queryParams = { clientId: applicationName };
|
||||
|
||||
return this.oAuth2Service.get<any[]>({ url, queryParams }).pipe(
|
||||
map((response) => response && response.length > 0 ? response[0].id : '')
|
||||
);
|
||||
return this.oAuth2Service.get<any[]>({ url, queryParams }).pipe(map((response) => (response && response.length > 0 ? response[0].id : '')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets client roles.
|
||||
*
|
||||
* @param groupId Id of the target group
|
||||
* @param clientId Id of the client
|
||||
* @returns List of roles
|
||||
@@ -267,20 +251,16 @@ export class IdentityGroupService implements IdentityGroupServiceInterface {
|
||||
|
||||
/**
|
||||
* Checks if a group has a client app.
|
||||
*
|
||||
* @param groupId Id of the target group
|
||||
* @param clientId Id of the client
|
||||
* @returns True if the group has the client app, false otherwise
|
||||
*/
|
||||
checkGroupHasClientApp(groupId: string, clientId: string): Observable<boolean> {
|
||||
return this.getClientRoles(groupId, clientId).pipe(
|
||||
map((response) => response && response.length > 0)
|
||||
);
|
||||
return this.getClientRoles(groupId, clientId).pipe(map((response) => response && response.length > 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a group has any of the client app roles in the supplied list.
|
||||
*
|
||||
* @param groupId Id of the target group
|
||||
* @param clientId Id of the client
|
||||
* @param roleNames Array of role names to check
|
||||
|
@@ -21,21 +21,31 @@ import { of, throwError } from 'rxjs';
|
||||
import { IdentityRoleResponseModel, IdentityRoleService } from './identity-role.service';
|
||||
|
||||
export const mockIdentityRole1 = {
|
||||
id: 'mock-id-1', name: 'Mock_Role_1', description: 'Mock desc1', clientRole: true, composite: false
|
||||
id: 'mock-id-1',
|
||||
name: 'Mock_Role_1',
|
||||
description: 'Mock desc1',
|
||||
clientRole: true,
|
||||
composite: false
|
||||
};
|
||||
|
||||
export const mockIdentityRole2 = {
|
||||
id: 'mock-id-2', name: 'Mock_Role_2', description: 'Mock desc2', clientRole: false, composite: true
|
||||
id: 'mock-id-2',
|
||||
name: 'Mock_Role_2',
|
||||
description: 'Mock desc2',
|
||||
clientRole: false,
|
||||
composite: true
|
||||
};
|
||||
|
||||
export const mockIdentityRole3 = {
|
||||
id: 'mock-id-3', name: 'Mock_Role_3', description: 'Mock desc3', clientRole: false, composite: false
|
||||
id: 'mock-id-3',
|
||||
name: 'Mock_Role_3',
|
||||
description: 'Mock desc3',
|
||||
clientRole: false,
|
||||
composite: false
|
||||
};
|
||||
|
||||
export const mockIdentityRoles = {
|
||||
entries: [
|
||||
mockIdentityRole1, mockIdentityRole2, mockIdentityRole3
|
||||
],
|
||||
entries: [mockIdentityRole1, mockIdentityRole2, mockIdentityRole3],
|
||||
pagination: {
|
||||
skipCount: 1,
|
||||
maxItems: 5,
|
||||
@@ -50,9 +60,7 @@ describe('IdentityRoleService', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientModule
|
||||
]
|
||||
imports: [HttpClientModule]
|
||||
});
|
||||
service = TestBed.inject(IdentityRoleService);
|
||||
});
|
||||
@@ -75,31 +83,29 @@ describe('IdentityRoleService', () => {
|
||||
statusText: 'Created'
|
||||
});
|
||||
spyOn(service, 'addRole').and.returnValue(of(response));
|
||||
service.addRole(mockIdentityRole1).subscribe(
|
||||
(res: any) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.status).toEqual(201);
|
||||
expect(res.statusText).toEqual('Created');
|
||||
done();
|
||||
}
|
||||
);
|
||||
service.addRole(mockIdentityRole1).subscribe((res: any) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.status).toEqual(201);
|
||||
expect(res.statusText).toEqual('Created');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not add role if error occurred', () => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'test 404 error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
status: 404,
|
||||
statusText: 'Not Found'
|
||||
});
|
||||
spyOn(service, 'addRole').and.returnValue(throwError(errorResponse));
|
||||
service.addRole(mockIdentityRole1)
|
||||
.subscribe(
|
||||
() => fail('expected an error'),
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('test 404 error');
|
||||
}
|
||||
);
|
||||
service.addRole(mockIdentityRole1).subscribe(
|
||||
() => fail('expected an error'),
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('test 404 error');
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to delete role', (done) => {
|
||||
@@ -109,30 +115,28 @@ describe('IdentityRoleService', () => {
|
||||
statusText: 'No Content'
|
||||
});
|
||||
spyOn(service, 'deleteRole').and.returnValue(of(response));
|
||||
service.deleteRole(mockIdentityRole1).subscribe(
|
||||
(res: any) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.status).toEqual(204);
|
||||
expect(res.statusText).toEqual('No Content');
|
||||
done();
|
||||
}
|
||||
);
|
||||
service.deleteRole(mockIdentityRole1).subscribe((res: any) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.status).toEqual(204);
|
||||
expect(res.statusText).toEqual('No Content');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not delete role if error occurred', () => {
|
||||
const errorResponse = new HttpErrorResponse({
|
||||
error: 'test 404 error',
|
||||
status: 404, statusText: 'Not Found'
|
||||
status: 404,
|
||||
statusText: 'Not Found'
|
||||
});
|
||||
spyOn(service, 'deleteRole').and.returnValue(throwError(errorResponse));
|
||||
service.deleteRole(mockIdentityRole1)
|
||||
.subscribe(
|
||||
() => fail('expected an error'),
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('test 404 error');
|
||||
}
|
||||
);
|
||||
service.deleteRole(mockIdentityRole1).subscribe(
|
||||
() => fail('expected an error'),
|
||||
(error) => {
|
||||
expect(error.status).toEqual(404);
|
||||
expect(error.statusText).toEqual('Not Found');
|
||||
expect(error.error).toEqual('test 404 error');
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@@ -42,7 +42,6 @@ export class IdentityRoleService {
|
||||
|
||||
/**
|
||||
* Ret all roles
|
||||
*
|
||||
* @param skipCount skip count
|
||||
* @param size page size
|
||||
* @returns List of roles
|
||||
@@ -66,7 +65,6 @@ export class IdentityRoleService {
|
||||
|
||||
/**
|
||||
* Add new role
|
||||
*
|
||||
* @param newRole Role model
|
||||
* @returns Server result payload
|
||||
*/
|
||||
@@ -79,7 +77,6 @@ export class IdentityRoleService {
|
||||
|
||||
/**
|
||||
* Delete existing role
|
||||
*
|
||||
* @param deletedRole Role model
|
||||
* @returns Server result payload
|
||||
*/
|
||||
@@ -89,7 +86,6 @@ export class IdentityRoleService {
|
||||
|
||||
/**
|
||||
* Update existing role
|
||||
*
|
||||
* @param updatedRole Role model
|
||||
* @param roleId Role id
|
||||
* @returns Server result payload
|
||||
|
@@ -22,7 +22,13 @@ import { AppConfigService } from '../../app-config/app-config.service';
|
||||
import { IdentityGroupModel } from '../models/identity-group.model';
|
||||
import { IdentityRoleModel } from '../models/identity-role.model';
|
||||
import { IdentityUserModel } from '../models/identity-user.model';
|
||||
import { IdentityJoinGroupRequestModel, IdentityUserServiceInterface, IdentityUserPasswordModel, IdentityUserQueryCloudRequestModel, IdentityUserQueryResponse } from '../interfaces/identity-user.service.interface';
|
||||
import {
|
||||
IdentityJoinGroupRequestModel,
|
||||
IdentityUserServiceInterface,
|
||||
IdentityUserPasswordModel,
|
||||
IdentityUserQueryCloudRequestModel,
|
||||
IdentityUserQueryResponse
|
||||
} from '../interfaces/identity-user.service.interface';
|
||||
import { JwtHelperService } from './jwt-helper.service';
|
||||
import { OAuth2Service } from './oauth2.service';
|
||||
|
||||
@@ -30,11 +36,7 @@ import { OAuth2Service } from './oauth2.service';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
constructor(
|
||||
private jwtHelperService: JwtHelperService,
|
||||
private oAuth2Service: OAuth2Service,
|
||||
private appConfigService: AppConfigService) { }
|
||||
constructor(private jwtHelperService: JwtHelperService, private oAuth2Service: OAuth2Service, private appConfigService: AppConfigService) {}
|
||||
|
||||
private get identityHost(): string {
|
||||
return `${this.appConfigService.get('identityHost')}`;
|
||||
@@ -46,7 +48,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets the name and other basic details of the current user.
|
||||
*
|
||||
* @returns The user's details
|
||||
*/
|
||||
getCurrentUserInfo(): IdentityUserModel {
|
||||
@@ -59,7 +60,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Find users based on search input.
|
||||
*
|
||||
* @param search Search query string
|
||||
* @returns List of users
|
||||
*/
|
||||
@@ -75,7 +75,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Find users based on username input.
|
||||
*
|
||||
* @param username Search query string
|
||||
* @returns List of users
|
||||
*/
|
||||
@@ -86,12 +85,11 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
const url = this.buildUserUrl();
|
||||
const queryParams = { username };
|
||||
|
||||
return this.oAuth2Service.get({url, queryParams });
|
||||
return this.oAuth2Service.get({ url, queryParams });
|
||||
}
|
||||
|
||||
/**
|
||||
* Find users based on email input.
|
||||
*
|
||||
* @param email Search query string
|
||||
* @returns List of users
|
||||
*/
|
||||
@@ -107,7 +105,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Find users based on id input.
|
||||
*
|
||||
* @param id Search query string
|
||||
* @returns users object
|
||||
*/
|
||||
@@ -121,7 +118,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Get client roles of a user for a particular client.
|
||||
*
|
||||
* @param userId ID of the target user
|
||||
* @param clientId ID of the client app
|
||||
* @returns List of client roles
|
||||
@@ -133,20 +129,16 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Checks whether user has access to a client app.
|
||||
*
|
||||
* @param userId ID of the target user
|
||||
* @param clientId ID of the client app
|
||||
* @returns True if the user has access, false otherwise
|
||||
*/
|
||||
checkUserHasClientApp(userId: string, clientId: string): Observable<boolean> {
|
||||
return this.getClientRoles(userId, clientId).pipe(
|
||||
map((clientRoles) => clientRoles.length > 0)
|
||||
);
|
||||
return this.getClientRoles(userId, clientId).pipe(map((clientRoles) => clientRoles.length > 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a user has any of the client app roles.
|
||||
*
|
||||
* @param userId ID of the target user
|
||||
* @param clientId ID of the client app
|
||||
* @param roleNames List of role names to check for
|
||||
@@ -173,7 +165,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets the client ID for an application.
|
||||
*
|
||||
* @param applicationName Name of the application
|
||||
* @returns Client ID string
|
||||
*/
|
||||
@@ -181,29 +172,21 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
const url = `${this.identityHost}/clients`;
|
||||
const queryParams = { clientId: applicationName };
|
||||
|
||||
return this.oAuth2Service
|
||||
.get<any[]>({url, queryParams })
|
||||
.pipe(
|
||||
map((response) => response && response.length > 0 ? response[0].id : '')
|
||||
);
|
||||
return this.oAuth2Service.get<any[]>({ url, queryParams }).pipe(map((response) => (response && response.length > 0 ? response[0].id : '')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user has access to an application.
|
||||
*
|
||||
* @param userId ID of the user
|
||||
* @param applicationName Name of the application
|
||||
* @returns True if the user has access, false otherwise
|
||||
*/
|
||||
checkUserHasApplicationAccess(userId: string, applicationName: string): Observable<boolean> {
|
||||
return this.getClientIdByApplicationName(applicationName).pipe(
|
||||
switchMap((clientId: string) => this.checkUserHasClientApp(userId, clientId))
|
||||
);
|
||||
return this.getClientIdByApplicationName(applicationName).pipe(switchMap((clientId: string) => this.checkUserHasClientApp(userId, clientId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user has any application role.
|
||||
*
|
||||
* @param userId ID of the target user
|
||||
* @param applicationName Name of the application
|
||||
* @param roleNames List of role names to check for
|
||||
@@ -217,7 +200,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets details for all users.
|
||||
*
|
||||
* @returns Array of user info objects
|
||||
*/
|
||||
getUsers(): Observable<IdentityUserModel[]> {
|
||||
@@ -227,7 +209,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets a list of roles for a user.
|
||||
*
|
||||
* @param userId ID of the user
|
||||
* @returns Array of role info objects
|
||||
*/
|
||||
@@ -238,7 +219,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets an array of users (including the current user) who have any of the roles in the supplied list.
|
||||
*
|
||||
* @param roleNames List of role names to look for
|
||||
* @returns Array of user info objects
|
||||
*/
|
||||
@@ -260,7 +240,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets an array of users (not including the current user) who have any of the roles in the supplied list.
|
||||
*
|
||||
* @param roleNames List of role names to look for
|
||||
* @returns Array of user info objects
|
||||
*/
|
||||
@@ -296,30 +275,30 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Checks if a user has one of the roles from a list.
|
||||
*
|
||||
* @param userId ID of the target user
|
||||
* @param roleNames Array of roles to check for
|
||||
* @returns True if the user has one of the roles, false otherwise
|
||||
*/
|
||||
checkUserHasRole(userId: string, roleNames: string[]): Observable<boolean> {
|
||||
return this.getUserRoles(userId).pipe(map((userRoles: IdentityRoleModel[]) => {
|
||||
let hasRole = false;
|
||||
if (userRoles && userRoles.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = userRoles.find(({ name }) => roleName === name);
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
}));
|
||||
return this.getUserRoles(userId).pipe(
|
||||
map((userRoles: IdentityRoleModel[]) => {
|
||||
let hasRole = false;
|
||||
if (userRoles && userRoles.length > 0) {
|
||||
roleNames.forEach((roleName: string) => {
|
||||
const role = userRoles.find(({ name }) => roleName === name);
|
||||
if (role) {
|
||||
hasRole = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return hasRole;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets details for all users.
|
||||
*
|
||||
* @param requestQuery query model
|
||||
* @returns Array of user information objects.
|
||||
*/
|
||||
@@ -330,16 +309,19 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
return this.getTotalUsersCount().pipe(
|
||||
switchMap((totalCount) =>
|
||||
this.oAuth2Service.get<IdentityUserModel[]>({ url, queryParams }).pipe(
|
||||
map((response) => ({
|
||||
entries: response,
|
||||
pagination: {
|
||||
skipCount: requestQuery.first,
|
||||
maxItems: requestQuery.max,
|
||||
count: totalCount,
|
||||
hasMoreItems: false,
|
||||
totalItems: totalCount
|
||||
}
|
||||
} as IdentityUserQueryResponse))
|
||||
map(
|
||||
(response) =>
|
||||
({
|
||||
entries: response,
|
||||
pagination: {
|
||||
skipCount: requestQuery.first,
|
||||
maxItems: requestQuery.max,
|
||||
count: totalCount,
|
||||
hasMoreItems: false,
|
||||
totalItems: totalCount
|
||||
}
|
||||
} as IdentityUserQueryResponse)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -347,7 +329,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets users total count.
|
||||
*
|
||||
* @returns Number of users count.
|
||||
*/
|
||||
getTotalUsersCount(): Observable<number> {
|
||||
@@ -357,7 +338,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Creates new user.
|
||||
*
|
||||
* @param newUser Object containing the new user details.
|
||||
* @returns Empty response when the user created.
|
||||
*/
|
||||
@@ -370,7 +350,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Updates user details.
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @param updatedUser Object containing the user details.
|
||||
* @returns Empty response when the user updated.
|
||||
@@ -384,7 +363,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Deletes User.
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @returns Empty response when the user deleted.
|
||||
*/
|
||||
@@ -395,7 +373,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Changes user password.
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @param newPassword Details of user Credentials.
|
||||
* @returns Empty response when the password changed.
|
||||
@@ -409,7 +386,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets involved groups.
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @returns Array of involved groups information objects.
|
||||
*/
|
||||
@@ -422,7 +398,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Joins group.
|
||||
*
|
||||
* @param joinGroupRequest Details of join group request (IdentityJoinGroupRequestModel).
|
||||
* @returns Empty response when the user joined the group.
|
||||
*/
|
||||
@@ -435,7 +410,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Leaves group.
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @param groupId Id of the group.
|
||||
* @returns Empty response when the user left the group.
|
||||
@@ -447,7 +421,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets available roles
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @returns Array of available roles information objects
|
||||
*/
|
||||
@@ -458,7 +431,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets assigned roles.
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @returns Array of assigned roles information objects
|
||||
*/
|
||||
@@ -471,7 +443,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Gets effective roles.
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @returns Array of composite roles information objects
|
||||
*/
|
||||
@@ -484,7 +455,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Assigns roles to the user.
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @param roles Array of roles.
|
||||
* @returns Empty response when the role assigned.
|
||||
@@ -498,7 +468,6 @@ export class IdentityUserService implements IdentityUserServiceInterface {
|
||||
|
||||
/**
|
||||
* Removes assigned roles.
|
||||
*
|
||||
* @param userId Id of the user.
|
||||
* @param removedRoles Array of roles.
|
||||
* @returns Empty response when the role removed.
|
||||
|
@@ -37,7 +37,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Decodes a JSON web token into a JS object.
|
||||
*
|
||||
* @param token Token in encoded form
|
||||
* @returns Decoded token data object
|
||||
*/
|
||||
@@ -79,7 +78,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Gets a named value from the user access or id token.
|
||||
*
|
||||
* @param key Key name of the field to retrieve
|
||||
* @returns Value from the token
|
||||
*/
|
||||
@@ -89,7 +87,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Gets a named value from the user access token.
|
||||
*
|
||||
* @param key Key name of the field to retrieve
|
||||
* @returns Value from the token
|
||||
*/
|
||||
@@ -99,7 +96,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Gets access token
|
||||
*
|
||||
* @returns access token
|
||||
*/
|
||||
getAccessToken(): string {
|
||||
@@ -108,7 +104,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Gets a named value from the user id token.
|
||||
*
|
||||
* @param key Key name of the field to retrieve
|
||||
* @returns Value from the token
|
||||
*/
|
||||
@@ -118,7 +113,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Gets id token
|
||||
*
|
||||
* @returns id token
|
||||
*/
|
||||
getIdToken(): string {
|
||||
@@ -127,7 +121,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Gets a named value from the user access token.
|
||||
*
|
||||
* @param token your SSO access token where the value is encode
|
||||
* @param key Key name of the field to retrieve
|
||||
* @returns Value from the token
|
||||
@@ -144,7 +137,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Gets realm roles.
|
||||
*
|
||||
* @returns Array of realm roles
|
||||
*/
|
||||
getRealmRoles(): string[] {
|
||||
@@ -154,7 +146,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Gets Client roles.
|
||||
*
|
||||
* @param clientName client name
|
||||
* @returns Array of client roles
|
||||
*/
|
||||
@@ -165,7 +156,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Checks for single realm role.
|
||||
*
|
||||
* @param role Role name to check
|
||||
* @returns True if it contains given role, false otherwise
|
||||
*/
|
||||
@@ -180,7 +170,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Checks for realm roles.
|
||||
*
|
||||
* @param rolesToCheck List of role names to check
|
||||
* @returns True if it contains at least one of the given roles, false otherwise
|
||||
*/
|
||||
@@ -190,7 +179,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Checks for client roles.
|
||||
*
|
||||
* @param clientName Targeted client name
|
||||
* @param rolesToCheck List of role names to check
|
||||
* @returns True if it contains at least one of the given roles, false otherwise
|
||||
@@ -201,7 +189,6 @@ export class JwtHelperService {
|
||||
|
||||
/**
|
||||
* Checks for client role.
|
||||
*
|
||||
* @param clientName Targeted client name
|
||||
* @param role Role name to check
|
||||
* @returns True if it contains given role, false otherwise
|
||||
|
@@ -36,17 +36,14 @@ export class OAuth2Service {
|
||||
request<T>(opts: OAuth2RequestParams): Observable<T> {
|
||||
const { httpMethod, url, bodyParam, queryParams } = opts;
|
||||
return from(
|
||||
this.adfHttpClient.request(
|
||||
url,
|
||||
{
|
||||
httpMethod,
|
||||
queryParams,
|
||||
headerParams: {},
|
||||
formParams: {},
|
||||
bodyParam,
|
||||
returnType: Object
|
||||
}
|
||||
)
|
||||
this.adfHttpClient.request(url, {
|
||||
httpMethod,
|
||||
queryParams,
|
||||
headerParams: {},
|
||||
formParams: {},
|
||||
bodyParam,
|
||||
returnType: Object
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -40,7 +40,6 @@ describe('UserAccessService', () => {
|
||||
|
||||
/**
|
||||
* spy on auth realm access
|
||||
*
|
||||
* @param realmRoles roles
|
||||
* @param resourceAccess access settings
|
||||
*/
|
||||
@@ -54,7 +53,6 @@ describe('UserAccessService', () => {
|
||||
|
||||
/**
|
||||
* spy on HxP authorisation
|
||||
*
|
||||
* @param appkey app key
|
||||
* @param roles roles list
|
||||
*/
|
||||
|
@@ -27,9 +27,7 @@ export class UserAccessService {
|
||||
private globalAccess: string[];
|
||||
private applicationAccess: ApplicationAccessModel[];
|
||||
|
||||
constructor(private jwtHelperService: JwtHelperService,
|
||||
private appConfigService: AppConfigService) {
|
||||
}
|
||||
constructor(private jwtHelperService: JwtHelperService, private appConfigService: AppConfigService) {}
|
||||
|
||||
fetchUserAccess() {
|
||||
if (this.hasRolesInRealmAccess()) {
|
||||
@@ -69,7 +67,6 @@ export class UserAccessService {
|
||||
|
||||
/**
|
||||
* Checks for global roles access.
|
||||
*
|
||||
* @param rolesToCheck List of the roles to check
|
||||
* @returns True if it contains at least one of the given roles, false otherwise
|
||||
*/
|
||||
@@ -93,15 +90,16 @@ export class UserAccessService {
|
||||
|
||||
/**
|
||||
* Checks for global roles access.
|
||||
*
|
||||
* @param appName The app name
|
||||
* @param rolesToCheck List of the roles to check
|
||||
* @returns True if it contains at least one of the given roles, false otherwise
|
||||
*/
|
||||
hasApplicationAccess(appName: string, rolesToCheck: string[]): boolean {
|
||||
if (rolesToCheck?.length > 0) {
|
||||
const appAccess = this.hasRolesInRealmAccess() ? this.applicationAccess[appName] : this.applicationAccess.find((app: ApplicationAccessModel) => app.name === appName);
|
||||
return appAccess ? appAccess.roles.some(appRole => rolesToCheck.includes(appRole)) : false;
|
||||
const appAccess = this.hasRolesInRealmAccess()
|
||||
? this.applicationAccess[appName]
|
||||
: this.applicationAccess.find((app: ApplicationAccessModel) => app.name === appName);
|
||||
return appAccess ? appAccess.roles.some((appRole) => rolesToCheck.includes(appRole)) : false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@@ -272,7 +272,6 @@ describe('CardViewComponent', () => {
|
||||
|
||||
/**
|
||||
* Return the card view item dispatcher component
|
||||
*
|
||||
* @returns the dispatcher component instance
|
||||
*/
|
||||
function getCardViewItemDispatcherComponent(): CardViewItemDispatcherComponent {
|
||||
|
@@ -27,7 +27,6 @@ export interface CardViewArrayItem {
|
||||
}
|
||||
|
||||
export class CardViewArrayItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||
|
||||
type: string = 'array';
|
||||
value: Observable<CardViewArrayItem[]>;
|
||||
noOfItemsToDisplay: number;
|
||||
|
@@ -117,18 +117,20 @@ describe('CardViewBaseItemModel', () => {
|
||||
const isValid = itemModel.isValid('test-against-this');
|
||||
|
||||
expect(isValid).toBe(false);
|
||||
expect(itemModel.getValidationErrors('test-against-this')).toEqual([validator1, validator3 ]);
|
||||
expect(itemModel.getValidationErrors('test-against-this')).toEqual([validator1, validator3]);
|
||||
});
|
||||
|
||||
it('should validate field with special character and return false when there is REGEX constraint and requiresMatch is false', () => {
|
||||
const constrainedProperties: CardViewItemProperties = {
|
||||
...properties,
|
||||
value: 'test.',
|
||||
constraints: [{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '(.*[\\"\\*\\\\\\>\\<\\?\\/\\:\\|]+.*)|(.*[\\.]?.*[\\.]+$)|(.*[ ]+$)', requiresMatch: false }
|
||||
}]
|
||||
constraints: [
|
||||
{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '(.*[\\"\\*\\\\\\>\\<\\?\\/\\:\\|]+.*)|(.*[\\.]?.*[\\.]+$)|(.*[ ]+$)', requiresMatch: false }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const itemModel = new CarViewCustomItemModel(constrainedProperties);
|
||||
@@ -138,11 +140,13 @@ describe('CardViewBaseItemModel', () => {
|
||||
it('should validate field without special character and return true when there is REGEX constraint and requiresMatch is false', () => {
|
||||
const constrainedProperties: CardViewItemProperties = {
|
||||
...properties,
|
||||
constraints: [{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '(.*[\\"\\*\\\\\\>\\<\\?\\/\\:\\|]+.*)|(.*[\\.]?.*[\\.]+$)|(.*[ ]+$)', requiresMatch: false }
|
||||
}]
|
||||
constraints: [
|
||||
{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '(.*[\\"\\*\\\\\\>\\<\\?\\/\\:\\|]+.*)|(.*[\\.]?.*[\\.]+$)|(.*[ ]+$)', requiresMatch: false }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const itemModel = new CarViewCustomItemModel(constrainedProperties);
|
||||
@@ -152,11 +156,13 @@ describe('CardViewBaseItemModel', () => {
|
||||
it('should validate field without special character and return false when there is REGEX constraint and requiresMatch is true', () => {
|
||||
const constrainedProperties: CardViewItemProperties = {
|
||||
...properties,
|
||||
constraints: [{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '(.*[\\"\\*\\\\\\>\\<\\?\\/\\:\\|]+.*)|(.*[\\.]?.*[\\.]+$)|(.*[ ]+$)', requiresMatch: true }
|
||||
}]
|
||||
constraints: [
|
||||
{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '(.*[\\"\\*\\\\\\>\\<\\?\\/\\:\\|]+.*)|(.*[\\.]?.*[\\.]+$)|(.*[ ]+$)', requiresMatch: true }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const itemModel = new CarViewCustomItemModel(constrainedProperties);
|
||||
@@ -167,11 +173,13 @@ describe('CardViewBaseItemModel', () => {
|
||||
const constrainedProperties: CardViewItemProperties = {
|
||||
...properties,
|
||||
value: 'test.',
|
||||
constraints: [{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '(.*[\\"\\*\\\\\\>\\<\\?\\/\\:\\|]+.*)|(.*[\\.]?.*[\\.]+$)|(.*[ ]+$)', requiresMatch: true }
|
||||
}]
|
||||
constraints: [
|
||||
{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '(.*[\\"\\*\\\\\\>\\<\\?\\/\\:\\|]+.*)|(.*[\\.]?.*[\\.]+$)|(.*[ ]+$)', requiresMatch: true }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const itemModel = new CarViewCustomItemModel(constrainedProperties);
|
||||
|
@@ -19,7 +19,6 @@ import { CardViewBoolItemModel } from './card-view-boolitem.model';
|
||||
import { CardViewBoolItemProperties } from '../interfaces/card-view.interfaces';
|
||||
|
||||
describe('CardViewFloatItemModel', () => {
|
||||
|
||||
let properties: CardViewBoolItemProperties;
|
||||
|
||||
beforeEach(() => {
|
||||
|
@@ -19,7 +19,6 @@ import { CardViewFloatItemModel } from './card-view-floatitem.model';
|
||||
import { CardViewTextItemProperties } from '../interfaces/card-view.interfaces';
|
||||
|
||||
describe('CardViewFloatItemModel', () => {
|
||||
|
||||
let properties: CardViewTextItemProperties;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -43,7 +42,7 @@ describe('CardViewFloatItemModel', () => {
|
||||
expect(itemModel.value).toBe(undefined);
|
||||
});
|
||||
|
||||
it('isValid should return the validator\'s value', () => {
|
||||
it("isValid should return the validator's value", () => {
|
||||
const itemModel = new CardViewFloatItemModel(properties);
|
||||
|
||||
expect(itemModel.isValid(42)).toBe(true, 'For 42 it should be true');
|
||||
@@ -63,11 +62,13 @@ describe('CardViewFloatItemModel', () => {
|
||||
value: '42.42',
|
||||
key: 'tribe',
|
||||
dataType: 'd:float',
|
||||
constraints: [{
|
||||
id: 'constraint-id',
|
||||
type: 'MINMAX',
|
||||
parameters: { minValue: 10, maxValue: 40 }
|
||||
}]
|
||||
constraints: [
|
||||
{
|
||||
id: 'constraint-id',
|
||||
type: 'MINMAX',
|
||||
parameters: { minValue: 10, maxValue: 40 }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const itemModel = new CardViewFloatItemModel(constrainedProperties);
|
||||
|
@@ -19,7 +19,6 @@ import { CardViewIntItemModel } from './card-view-intitem.model';
|
||||
import { CardViewTextItemProperties } from '../interfaces/card-view.interfaces';
|
||||
|
||||
describe('CardViewIntItemModel', () => {
|
||||
|
||||
let properties: CardViewTextItemProperties;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -43,7 +42,7 @@ describe('CardViewIntItemModel', () => {
|
||||
expect(itemModel.value).toBe(undefined);
|
||||
});
|
||||
|
||||
it('isValid should return the validator\'s value', () => {
|
||||
it("isValid should return the validator's value", () => {
|
||||
const itemModel = new CardViewIntItemModel(properties);
|
||||
|
||||
expect(itemModel.isValid(42)).toBe(true, 'For 42 it should be true');
|
||||
@@ -63,11 +62,13 @@ describe('CardViewIntItemModel', () => {
|
||||
value: '20',
|
||||
key: 'tribe',
|
||||
dataType: 'd:float',
|
||||
constraints: [{
|
||||
id: 'constraint-id',
|
||||
type: 'MINMAX',
|
||||
parameters: { minValue: 10, maxValue: 15 }
|
||||
}]
|
||||
constraints: [
|
||||
{
|
||||
id: 'constraint-id',
|
||||
type: 'MINMAX',
|
||||
parameters: { minValue: 10, maxValue: 15 }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const itemModel = new CardViewIntItemModel(constrainedProperties);
|
||||
|
@@ -27,7 +27,6 @@ class TestPipe implements PipeTransform {
|
||||
}
|
||||
|
||||
describe('CardViewTextItemModel', () => {
|
||||
|
||||
let properties: CardViewTextItemProperties;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -39,7 +38,6 @@ describe('CardViewTextItemModel', () => {
|
||||
});
|
||||
|
||||
describe('displayValue', () => {
|
||||
|
||||
it('should return the value if it is present', () => {
|
||||
const itemModel = new CardViewTextItemModel(properties);
|
||||
|
||||
@@ -56,18 +54,14 @@ describe('CardViewTextItemModel', () => {
|
||||
});
|
||||
|
||||
it('should apply a pipe on the value if it is present', () => {
|
||||
properties.pipes = [
|
||||
{ pipe: new TestPipe() }
|
||||
];
|
||||
properties.pipes = [{ pipe: new TestPipe() }];
|
||||
const itemModel = new CardViewTextItemModel(properties);
|
||||
|
||||
expect(itemModel.displayValue).toBe('testpiped-Banuk');
|
||||
});
|
||||
|
||||
it('should apply a pipe on the value with parameters if those are present', () => {
|
||||
properties.pipes = [
|
||||
{ pipe: new TestPipe(), params: ['withParams'] }
|
||||
];
|
||||
properties.pipes = [{ pipe: new TestPipe(), params: ['withParams'] }];
|
||||
const itemModel = new CardViewTextItemModel(properties);
|
||||
|
||||
expect(itemModel.displayValue).toBe('testpiped-Banuk-withParams');
|
||||
@@ -91,11 +85,13 @@ describe('CardViewTextItemModel', () => {
|
||||
label: 'Tribe',
|
||||
value: 'test',
|
||||
key: 'tribe',
|
||||
constraints: [{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '^(?=.*test).*', requiresMatch: true }
|
||||
}]
|
||||
constraints: [
|
||||
{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '^(?=.*test).*', requiresMatch: true }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const itemModel = new CardViewTextItemModel(constrainedProperties);
|
||||
@@ -110,11 +106,13 @@ describe('CardViewTextItemModel', () => {
|
||||
label: 'Tribe',
|
||||
value: 'test',
|
||||
key: 'tribe',
|
||||
constraints: [{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '^(?=.*test).*', requiresMatch: false }
|
||||
}]
|
||||
constraints: [
|
||||
{
|
||||
id: 'constraint-id',
|
||||
type: 'REGEX',
|
||||
parameters: { expression: '^(?=.*test).*', requiresMatch: false }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const itemModel = new CardViewTextItemModel(constrainedProperties);
|
||||
|
@@ -20,9 +20,7 @@ import { CardViewBaseItemModel } from '../models/card-view-baseitem.model';
|
||||
import { CardViewUpdateService, transformKeyToObject } from './card-view-update.service';
|
||||
|
||||
describe('CardViewUpdateService', () => {
|
||||
|
||||
describe('transformKeyToObject', () => {
|
||||
|
||||
it('should return the proper constructed value object for "dotless" keys', () => {
|
||||
const valueObject = transformKeyToObject('property-key', 'property-value');
|
||||
|
||||
@@ -47,7 +45,6 @@ describe('CardViewUpdateService', () => {
|
||||
});
|
||||
|
||||
describe('Service', () => {
|
||||
|
||||
let cardViewUpdateService: CardViewUpdateService;
|
||||
const property: CardViewBaseItemModel = {
|
||||
label: 'property-label',
|
||||
@@ -63,23 +60,17 @@ describe('CardViewUpdateService', () => {
|
||||
});
|
||||
|
||||
it('should send updated message with proper parameters', fakeAsync(() => {
|
||||
|
||||
cardViewUpdateService.itemUpdated$.subscribe(
|
||||
( { target, changed } ) => {
|
||||
expect(target).toBe(property);
|
||||
expect(changed).toEqual({ 'property-key': 'changed-property-value' });
|
||||
}
|
||||
);
|
||||
cardViewUpdateService.itemUpdated$.subscribe(({ target, changed }) => {
|
||||
expect(target).toBe(property);
|
||||
expect(changed).toEqual({ 'property-key': 'changed-property-value' });
|
||||
});
|
||||
cardViewUpdateService.update(property, 'changed-property-value');
|
||||
}));
|
||||
|
||||
it('should send clicked message with proper parameters', fakeAsync(() => {
|
||||
|
||||
cardViewUpdateService.itemClicked$.subscribe(
|
||||
( { target } ) => {
|
||||
expect(target).toBe(property);
|
||||
}
|
||||
);
|
||||
cardViewUpdateService.itemClicked$.subscribe(({ target }) => {
|
||||
expect(target).toBe(property);
|
||||
});
|
||||
cardViewUpdateService.clicked(property);
|
||||
}));
|
||||
});
|
||||
|
@@ -52,7 +52,6 @@ export class CardViewUpdateService implements BaseCardViewUpdate {
|
||||
|
||||
/**
|
||||
* Updates the cardview items property
|
||||
*
|
||||
* @param notification notification value
|
||||
*/
|
||||
updateElement(notification: CardViewBaseItemModel) {
|
||||
|
@@ -18,7 +18,6 @@
|
||||
import { CardViewItemValidator } from '../interfaces/card-view.interfaces';
|
||||
|
||||
export class CardViewItemFloatValidator implements CardViewItemValidator {
|
||||
|
||||
message = 'CORE.CARDVIEW.VALIDATORS.FLOAT_VALIDATION_ERROR';
|
||||
|
||||
isValid(value: any | any[]): boolean {
|
||||
|
@@ -18,7 +18,6 @@
|
||||
import { CardViewItemValidator } from '../interfaces/card-view.interfaces';
|
||||
|
||||
export class CardViewItemIntValidator implements CardViewItemValidator {
|
||||
|
||||
message = 'CORE.CARDVIEW.VALIDATORS.INT_VALIDATION_ERROR';
|
||||
|
||||
isValid(value: any | any[]): boolean {
|
||||
@@ -26,7 +25,7 @@ export class CardViewItemIntValidator implements CardViewItemValidator {
|
||||
return value.every(this.isIntegerNumber);
|
||||
}
|
||||
|
||||
return value === '' || !isNaN(value) && this.isIntegerNumber(value) && this.isNotOnlySpace(value);
|
||||
return value === '' || (!isNaN(value) && this.isIntegerNumber(value) && this.isNotOnlySpace(value));
|
||||
}
|
||||
|
||||
isIntegerNumber(value: any): boolean {
|
||||
|
@@ -27,11 +27,7 @@ export class CardViewItemPositiveIntValidator implements CardViewItemValidator {
|
||||
|
||||
const valueIsNotSet = value === '';
|
||||
|
||||
return valueIsNotSet ||
|
||||
(
|
||||
!isNaN(value) &&
|
||||
this.isPositiveNumber(value)
|
||||
);
|
||||
return valueIsNotSet || (!isNaN(value) && this.isPositiveNumber(value));
|
||||
}
|
||||
|
||||
private isPositiveNumber(value: any): boolean {
|
||||
|
@@ -25,7 +25,6 @@ export class ClipboardService {
|
||||
|
||||
/**
|
||||
* Checks if the target element can have its text copied.
|
||||
*
|
||||
* @param target Target HTML element
|
||||
* @returns True if the text can be copied, false otherwise
|
||||
*/
|
||||
@@ -38,7 +37,6 @@ export class ClipboardService {
|
||||
|
||||
/**
|
||||
* Copies text from an HTML element to the clipboard.
|
||||
*
|
||||
* @param target HTML element to be copied
|
||||
* @param message Snackbar message to alert when copying happens
|
||||
*/
|
||||
@@ -61,7 +59,6 @@ export class ClipboardService {
|
||||
|
||||
/**
|
||||
* Copies a text string to the clipboard.
|
||||
*
|
||||
* @param content Text to copy
|
||||
* @param message Snackbar message to alert when copying happens
|
||||
*/
|
||||
|
@@ -20,7 +20,6 @@ import { Observable, of } from 'rxjs';
|
||||
import { CommentsService } from '../interfaces/comments-service.interface';
|
||||
|
||||
export class CommentsServiceMock implements Partial<CommentsService> {
|
||||
|
||||
constructor() {}
|
||||
|
||||
get(_id: string): Observable<CommentModel[]> {
|
||||
@@ -40,36 +39,38 @@ const commentUser = new User({
|
||||
});
|
||||
|
||||
export const commentsResponseMock = {
|
||||
getComments: () => of([
|
||||
new CommentModel({
|
||||
id: 1,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 2,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 3,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
})
|
||||
]),
|
||||
addComment: (message = 'test comment') => of(
|
||||
new CommentModel({
|
||||
id: 1,
|
||||
message,
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
})
|
||||
)
|
||||
getComments: () =>
|
||||
of([
|
||||
new CommentModel({
|
||||
id: 1,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 2,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 3,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
})
|
||||
]),
|
||||
addComment: (message = 'test comment') =>
|
||||
of(
|
||||
new CommentModel({
|
||||
id: 1,
|
||||
message,
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
})
|
||||
)
|
||||
};
|
||||
|
@@ -21,7 +21,6 @@ import { CommentsService } from '../interfaces/comments-service.interface';
|
||||
import { testUser } from './comments.stories.mock';
|
||||
|
||||
export class CommentsServiceStoriesMock implements Partial<CommentsService> {
|
||||
|
||||
constructor() {}
|
||||
|
||||
get(_id: string): Observable<CommentModel[]> {
|
||||
@@ -41,36 +40,38 @@ const commentUser = new User({
|
||||
});
|
||||
|
||||
export const commentsResponseMock = {
|
||||
getComments: () => of([
|
||||
new CommentModel({
|
||||
id: 1,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 2,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 3,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
})
|
||||
]),
|
||||
addComment: (message: string) => of(
|
||||
new CommentModel({
|
||||
id: 1,
|
||||
message,
|
||||
created: new Date(),
|
||||
createdBy: testUser,
|
||||
isSelected: false
|
||||
})
|
||||
)
|
||||
getComments: () =>
|
||||
of([
|
||||
new CommentModel({
|
||||
id: 1,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 2,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 3,
|
||||
message: 'Test Comment',
|
||||
created: new Date(),
|
||||
createdBy: commentUser,
|
||||
isSelected: false
|
||||
})
|
||||
]),
|
||||
addComment: (message: string) =>
|
||||
of(
|
||||
new CommentModel({
|
||||
id: 1,
|
||||
message,
|
||||
created: new Date(),
|
||||
createdBy: testUser,
|
||||
isSelected: false
|
||||
})
|
||||
)
|
||||
};
|
||||
|
@@ -72,35 +72,34 @@ export const testUser: any = {
|
||||
avatarId: '044'
|
||||
};
|
||||
|
||||
|
||||
export const commentsStoriesData: CommentModel[] = [
|
||||
new CommentModel({
|
||||
id: 1,
|
||||
message: `I've done this task, what's next?`,
|
||||
created: getDateXMinutesAgo(30),
|
||||
createdBy: johnDoe,
|
||||
isSelected: false
|
||||
id: 1,
|
||||
message: `I've done this task, what's next?`,
|
||||
created: getDateXMinutesAgo(30),
|
||||
createdBy: johnDoe,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 2,
|
||||
message: `I've assigned you another one 🤠`,
|
||||
created: getDateXMinutesAgo(15),
|
||||
createdBy: janeEod,
|
||||
isSelected: false
|
||||
id: 2,
|
||||
message: `I've assigned you another one 🤠`,
|
||||
created: getDateXMinutesAgo(15),
|
||||
createdBy: janeEod,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 3,
|
||||
message: '+1',
|
||||
created: getDateXMinutesAgo(12),
|
||||
createdBy: robertSmith,
|
||||
isSelected: false
|
||||
id: 3,
|
||||
message: '+1',
|
||||
created: getDateXMinutesAgo(12),
|
||||
createdBy: robertSmith,
|
||||
isSelected: false
|
||||
}),
|
||||
new CommentModel({
|
||||
id: 4,
|
||||
message: 'Cheers',
|
||||
created: new Date(),
|
||||
createdBy: johnDoe,
|
||||
isSelected: false
|
||||
id: 4,
|
||||
message: 'Cheers',
|
||||
created: new Date(),
|
||||
createdBy: johnDoe,
|
||||
isSelected: false
|
||||
})
|
||||
];
|
||||
|
||||
|
@@ -25,10 +25,10 @@ export class LogLevelsEnum extends Number {
|
||||
}
|
||||
|
||||
export const logLevels: any[] = [
|
||||
{level: LogLevelsEnum.TRACE, name: 'TRACE'},
|
||||
{level: LogLevelsEnum.DEBUG, name: 'DEBUG'},
|
||||
{level: LogLevelsEnum.INFO, name: 'INFO'},
|
||||
{level: LogLevelsEnum.WARN, name: 'WARN'},
|
||||
{level: LogLevelsEnum.ERROR, name: 'ERROR'},
|
||||
{level: LogLevelsEnum.SILENT, name: 'SILENT'}
|
||||
{ level: LogLevelsEnum.TRACE, name: 'TRACE' },
|
||||
{ level: LogLevelsEnum.DEBUG, name: 'DEBUG' },
|
||||
{ level: LogLevelsEnum.INFO, name: 'INFO' },
|
||||
{ level: LogLevelsEnum.WARN, name: 'WARN' },
|
||||
{ level: LogLevelsEnum.ERROR, name: 'ERROR' },
|
||||
{ level: LogLevelsEnum.SILENT, name: 'SILENT' }
|
||||
];
|
||||
|
@@ -21,7 +21,6 @@ import { Injectable } from '@angular/core';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CookieService {
|
||||
|
||||
cookieEnabled = false;
|
||||
|
||||
constructor() {
|
||||
@@ -37,7 +36,6 @@ export class CookieService {
|
||||
|
||||
/**
|
||||
* Checks if cookies are enabled.
|
||||
*
|
||||
* @returns True if enabled, false otherwise
|
||||
*/
|
||||
isEnabled(): boolean {
|
||||
@@ -46,39 +44,33 @@ export class CookieService {
|
||||
|
||||
/**
|
||||
* Retrieves a cookie by its key.
|
||||
*
|
||||
* @param key Key to identify the cookie
|
||||
* @returns The cookie data or null if it is not found
|
||||
*/
|
||||
getItem(key: string): string | null {
|
||||
const regexp = new RegExp('(?:' + key + '|;\\s*' + key + ')=(.*?)(?:;|$)', 'g');
|
||||
const result = regexp.exec(document.cookie);
|
||||
return (result === null) ? null : result[1];
|
||||
return result === null ? null : result[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a cookie.
|
||||
*
|
||||
* @param key Key to identify the cookie
|
||||
* @param data Data value to set for the cookie
|
||||
* @param expiration Expiration date of the data
|
||||
* @param path "Pathname" to store the cookie
|
||||
*/
|
||||
setItem(key: string, data: string, expiration: Date | null = null, path: string | null = null): void {
|
||||
document.cookie = `${key}=${data}` +
|
||||
(expiration ? ';expires=' + expiration.toUTCString() : '') +
|
||||
(path ? `;path=${path}` : ';path=/');
|
||||
document.cookie = `${key}=${data}` + (expiration ? ';expires=' + expiration.toUTCString() : '') + (path ? `;path=${path}` : ';path=/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cookie Key.
|
||||
*
|
||||
* @param key Key to identify the cookie
|
||||
* @param path "Pathname" to store the cookie
|
||||
*/
|
||||
deleteCookie(key: string, path: string | null = null): void {
|
||||
document.cookie = key + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;' +
|
||||
(path ? `;path=${path}` : ';path=/');
|
||||
document.cookie = key + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;' + (path ? `;path=${path}` : ';path=/');
|
||||
}
|
||||
|
||||
/** Placeholder for testing purposes - do not use. */
|
||||
|
@@ -42,8 +42,7 @@ export class DownloadService {
|
||||
}
|
||||
|
||||
if (blob) {
|
||||
if (typeof window.navigator !== 'undefined' &&
|
||||
window.navigator['msSaveOrOpenBlob']) {
|
||||
if (window.navigator?.['msSaveOrOpenBlob']) {
|
||||
window.navigator['msSaveOrOpenBlob'](blob, fileName);
|
||||
} else {
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
@@ -60,7 +59,6 @@ export class DownloadService {
|
||||
|
||||
/**
|
||||
* Invokes content download for a Blob with a file name.
|
||||
*
|
||||
* @param blob Content to download.
|
||||
* @param fileName Name of the resulting file.
|
||||
*/
|
||||
@@ -70,7 +68,6 @@ export class DownloadService {
|
||||
|
||||
/**
|
||||
* Invokes content download for a data array with a file name.
|
||||
*
|
||||
* @param data Data to download.
|
||||
* @param fileName Name of the resulting file.
|
||||
*/
|
||||
@@ -80,7 +77,6 @@ export class DownloadService {
|
||||
|
||||
/**
|
||||
* Invokes content download for a JSON object with a file name.
|
||||
*
|
||||
* @param json JSON object to download.
|
||||
* @param fileName Name of the resulting file.
|
||||
*/
|
||||
@@ -90,7 +86,6 @@ export class DownloadService {
|
||||
|
||||
/**
|
||||
* Invokes the download of the file by its URL address.
|
||||
*
|
||||
* @param url Url address pointing to the file.
|
||||
* @param fileName Name of the file download.
|
||||
*/
|
||||
|
@@ -17,10 +17,13 @@
|
||||
|
||||
import { Type } from '@angular/core';
|
||||
|
||||
const getType = (type: any): any => () => type;
|
||||
const getType =
|
||||
(type: any): any =>
|
||||
() =>
|
||||
type;
|
||||
|
||||
export interface DynamicComponentModel {
|
||||
type: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export type DynamicComponentResolveFunction = (model: DynamicComponentModel) => Type<any>;
|
||||
@@ -31,13 +34,11 @@ export class DynamicComponentResolver {
|
||||
}
|
||||
|
||||
export abstract class DynamicComponentMapper {
|
||||
|
||||
protected defaultValue: Type<any> = undefined;
|
||||
protected types: { [key: string]: DynamicComponentResolveFunction } = {};
|
||||
|
||||
/**
|
||||
* Gets the currently active DynamicComponentResolveFunction for a field type.
|
||||
*
|
||||
* @param type The type whose resolver you want
|
||||
* @param defaultValue Default type returned for types that are not yet mapped
|
||||
* @returns Resolver function
|
||||
@@ -51,7 +52,6 @@ export abstract class DynamicComponentMapper {
|
||||
|
||||
/**
|
||||
* Sets or optionally replaces a DynamicComponentResolveFunction for a field type.
|
||||
*
|
||||
* @param type The type whose resolver you want to set
|
||||
* @param resolver The new resolver function
|
||||
* @param override The new resolver will only replace an existing one if this parameter is true
|
||||
@@ -75,7 +75,6 @@ export abstract class DynamicComponentMapper {
|
||||
|
||||
/**
|
||||
* Register multiple components
|
||||
*
|
||||
* @param components map of components to register
|
||||
* @param override replace existing components
|
||||
*/
|
||||
@@ -89,7 +88,6 @@ export abstract class DynamicComponentMapper {
|
||||
|
||||
/**
|
||||
* Finds the component type that is needed to render a form field.
|
||||
*
|
||||
* @param model Form field model for the field to render
|
||||
* @param defaultValue Default type returned for field types that are not yet mapped.
|
||||
* @returns Component type
|
||||
|
@@ -26,10 +26,8 @@ export interface HighlightTransformResult {
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class HighlightTransformService {
|
||||
|
||||
/**
|
||||
* Searches for `search` string(s) within `text` and highlights all occurrences.
|
||||
*
|
||||
* @param text Text to search within
|
||||
* @param search Text pattern to search for
|
||||
* @param wrapperClass CSS class used to provide highlighting style
|
||||
@@ -42,7 +40,10 @@ export class HighlightTransformService {
|
||||
if (search && text) {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
let pattern = search.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
||||
pattern = pattern.split(' ').filter((t) => t.length > 0).join('|');
|
||||
pattern = pattern
|
||||
.split(' ')
|
||||
.filter((t) => t.length > 0)
|
||||
.join('|');
|
||||
|
||||
const regex = new RegExp(pattern, 'gi');
|
||||
result = this.removeHtmlTags(text).replace(regex, (match) => {
|
||||
|
@@ -166,11 +166,9 @@ describe('LogService', () => {
|
||||
it('message Observable', fakeAsync(() => {
|
||||
appConfigService.config['logLevel'] = 'trace';
|
||||
|
||||
providesLogComponent.componentInstance.logService.onMessage.subscribe(
|
||||
(message) => {
|
||||
expect(message).toEqual({ text: 'Test message', type: 'LOG' });
|
||||
}
|
||||
);
|
||||
providesLogComponent.componentInstance.logService.onMessage.subscribe((message) => {
|
||||
expect(message).toEqual({ text: 'Test message', type: 'LOG' });
|
||||
});
|
||||
|
||||
providesLogComponent.componentInstance.log();
|
||||
}));
|
||||
|
@@ -47,7 +47,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Logs a message at the "ERROR" level.
|
||||
*
|
||||
* @param message Message to log
|
||||
* @param optionalParams Interpolation values for the message in "printf" format
|
||||
*/
|
||||
@@ -61,7 +60,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Logs a message at the "DEBUG" level.
|
||||
*
|
||||
* @param message Message to log
|
||||
* @param optionalParams Interpolation values for the message in "printf" format
|
||||
*/
|
||||
@@ -75,7 +73,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Logs a message at the "INFO" level.
|
||||
*
|
||||
* @param message Message to log
|
||||
* @param optionalParams Interpolation values for the message in "printf" format
|
||||
*/
|
||||
@@ -89,7 +86,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Logs a message at any level from "TRACE" upwards.
|
||||
*
|
||||
* @param message Message to log
|
||||
* @param optionalParams Interpolation values for the message in "printf" format
|
||||
*/
|
||||
@@ -103,7 +99,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Logs a message at the "TRACE" level.
|
||||
*
|
||||
* @param message Message to log
|
||||
* @param optionalParams Interpolation values for the message in "printf" format
|
||||
*/
|
||||
@@ -117,7 +112,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Logs a message at the "WARN" level.
|
||||
*
|
||||
* @param message Message to log
|
||||
* @param optionalParams Interpolation values for the message in "printf" format
|
||||
*/
|
||||
@@ -131,7 +125,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Logs a message if a boolean test fails.
|
||||
*
|
||||
* @param test Test value (typically a boolean expression)
|
||||
* @param message Message to show if test is false
|
||||
* @param optionalParams Interpolation values for the message in "printf" format
|
||||
@@ -146,7 +139,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Starts an indented group of log messages.
|
||||
*
|
||||
* @param groupTitle Title shown at the start of the group
|
||||
* @param optionalParams Interpolation values for the title in "printf" format
|
||||
*/
|
||||
@@ -167,7 +159,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Converts a log level name string into its numeric equivalent.
|
||||
*
|
||||
* @param level Level name
|
||||
* @returns Numeric log level
|
||||
*/
|
||||
@@ -179,7 +170,6 @@ export class LogService {
|
||||
|
||||
/**
|
||||
* Triggers notification callback for log messages.
|
||||
*
|
||||
* @param text Message text
|
||||
* @param logLevel Log level for the message
|
||||
*/
|
||||
|
@@ -24,21 +24,16 @@ import { TranslationService } from '../../translation/translation.service';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PageTitleService {
|
||||
|
||||
private originalTitle: string = '';
|
||||
private translatedTitle: string = '';
|
||||
|
||||
constructor(
|
||||
private titleService: Title,
|
||||
private appConfig: AppConfigService,
|
||||
private translationService: TranslationService) {
|
||||
constructor(private titleService: Title, private appConfig: AppConfigService, private translationService: TranslationService) {
|
||||
translationService.translate.onLangChange.subscribe(() => this.onLanguageChanged());
|
||||
translationService.translate.onTranslationChange.subscribe(() => this.onLanguageChanged());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the page title.
|
||||
*
|
||||
* @param value The new title
|
||||
*/
|
||||
setTitle(value: string = '') {
|
||||
|
@@ -39,7 +39,6 @@ export class StorageService {
|
||||
|
||||
/**
|
||||
* Gets an item.
|
||||
*
|
||||
* @param key Key to identify the item
|
||||
* @returns The item (if any) retrieved by the key
|
||||
*/
|
||||
@@ -53,7 +52,6 @@ export class StorageService {
|
||||
|
||||
/**
|
||||
* Stores an item
|
||||
*
|
||||
* @param key Key to identify the item
|
||||
* @param data Data to store
|
||||
*/
|
||||
@@ -76,7 +74,6 @@ export class StorageService {
|
||||
|
||||
/**
|
||||
* Removes a single item.
|
||||
*
|
||||
* @param key Key to identify the item
|
||||
*/
|
||||
removeItem(key: string) {
|
||||
@@ -89,7 +86,6 @@ export class StorageService {
|
||||
|
||||
/**
|
||||
* Is any item currently stored under `key`?
|
||||
*
|
||||
* @param key Key identifying item to check
|
||||
* @returns True if key retrieves an item, false otherwise
|
||||
*/
|
||||
|
@@ -172,18 +172,16 @@ export class ThumbnailService {
|
||||
|
||||
/**
|
||||
* Gets a thumbnail URL for a MIME type.
|
||||
*
|
||||
* @param mimeType MIME type for the thumbnail
|
||||
* @returns URL string
|
||||
*/
|
||||
public getMimeTypeIcon(mimeType: string): string {
|
||||
const icon = this.mimeTypeIcons[mimeType];
|
||||
return (icon || DEFAULT_ICON);
|
||||
return icon || DEFAULT_ICON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a "miscellaneous" thumbnail URL for types with no other icon defined.
|
||||
*
|
||||
* @returns URL string
|
||||
*/
|
||||
getDefaultMimeTypeIcon(): string {
|
||||
|
@@ -22,14 +22,11 @@ import { DomSanitizer } from '@angular/platform-browser';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UrlService {
|
||||
|
||||
constructor(private sanitizer: DomSanitizer) {
|
||||
}
|
||||
constructor(private sanitizer: DomSanitizer) {}
|
||||
|
||||
/**
|
||||
* Creates a trusted object URL from the Blob.
|
||||
* WARNING: calling this method with untrusted user data exposes your application to XSS security risks!
|
||||
*
|
||||
* @param blob Data to wrap into object URL
|
||||
* @returns URL string
|
||||
*/
|
||||
@@ -37,6 +34,4 @@ export class UrlService {
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
return this.sanitizer.bypassSecurityTrustUrl(url) as string;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -90,7 +90,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Sets up a callback to notify when a property has changed.
|
||||
*
|
||||
* @param property The property to watch
|
||||
* @returns Notification callback
|
||||
*/
|
||||
@@ -103,7 +102,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Gets a preference property.
|
||||
*
|
||||
* @param property Name of the property
|
||||
* @param defaultValue Default to return if the property is not found
|
||||
* @returns Preference property
|
||||
@@ -119,7 +117,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Sets a preference property.
|
||||
*
|
||||
* @param property Name of the property
|
||||
* @param value New value for the property
|
||||
*/
|
||||
@@ -134,7 +131,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Sets a preference property.
|
||||
*
|
||||
* @param property Name of the property
|
||||
* @param value New value for the property
|
||||
*/
|
||||
@@ -148,7 +144,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Check if an item is present in the storage
|
||||
*
|
||||
* @param property Name of the property
|
||||
* @returns True if the item is present, false otherwise
|
||||
*/
|
||||
@@ -161,7 +156,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Gets the active storage prefix for preferences.
|
||||
*
|
||||
* @returns Storage prefix
|
||||
*/
|
||||
getStoragePrefix(): string {
|
||||
@@ -170,7 +164,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Sets the active storage prefix for preferences.
|
||||
*
|
||||
* @param value Name of the prefix
|
||||
*/
|
||||
setStoragePrefix(value: string | null) {
|
||||
@@ -180,7 +173,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Gets the full property key with prefix.
|
||||
*
|
||||
* @param property The property name
|
||||
* @returns Property key
|
||||
*/
|
||||
@@ -190,7 +182,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Gets an array containing the available page sizes.
|
||||
*
|
||||
* @returns Array of page size values
|
||||
*/
|
||||
get supportedPageSizes(): number[] {
|
||||
@@ -224,7 +215,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Current locale setting.
|
||||
*
|
||||
* @returns locale name
|
||||
*/
|
||||
get locale(): string {
|
||||
@@ -237,7 +227,6 @@ export class UserPreferencesService {
|
||||
|
||||
/**
|
||||
* Gets the default locale.
|
||||
*
|
||||
* @returns Default locale language code
|
||||
*/
|
||||
getDefaultLocale(): string {
|
||||
|
@@ -27,7 +27,6 @@ import { isValid, Locale, parse } from 'date-fns';
|
||||
*
|
||||
* Automatically switches locales based on user preferences.
|
||||
* Supports custom display format.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* Add the following to the component `providers` section
|
||||
|
@@ -101,7 +101,6 @@ export class DateFnsUtils {
|
||||
|
||||
/**
|
||||
* Converts a Moment.js date format string to the equivalent date-fns format string.
|
||||
*
|
||||
* @param dateDisplayFormat - The Moment.js date format string to convert.
|
||||
* @returns The equivalent date-fns format string.
|
||||
*/
|
||||
@@ -120,7 +119,6 @@ export class DateFnsUtils {
|
||||
|
||||
/**
|
||||
* Formats a date using the specified date format.
|
||||
*
|
||||
* @param date - The date to format, can be a number or a Date object.
|
||||
* @param dateFormat - The date format string to use for formatting.
|
||||
* @returns The formatted date as a string
|
||||
@@ -134,7 +132,6 @@ export class DateFnsUtils {
|
||||
|
||||
/**
|
||||
* Parses a date string using the specified date format.
|
||||
*
|
||||
* @param value - The date value to parse. Can be a string or a Date (for generic calls)
|
||||
* @param dateFormat - The date format string to use for parsing.
|
||||
* @param options - Additional options
|
||||
@@ -157,7 +154,6 @@ export class DateFnsUtils {
|
||||
|
||||
/**
|
||||
* Parses a datetime string using the ISO format
|
||||
*
|
||||
* @param value - The date and time string to parse
|
||||
* @returns returns the parsed Date object
|
||||
*/
|
||||
@@ -167,7 +163,6 @@ export class DateFnsUtils {
|
||||
|
||||
/**
|
||||
* Checks if the date string is a valid date according to the specified format
|
||||
*
|
||||
* @param dateValue Date value
|
||||
* @param dateFormat The date format
|
||||
* @returns `true` if the date is valid, otherwise `false`
|
||||
@@ -182,7 +177,6 @@ export class DateFnsUtils {
|
||||
|
||||
/**
|
||||
* Validates a date is before another one
|
||||
*
|
||||
* @param source source date to compare
|
||||
* @param target target date to compare
|
||||
* @returns `true` if the source date is before the target one, otherwise `false`
|
||||
@@ -193,7 +187,6 @@ export class DateFnsUtils {
|
||||
|
||||
/**
|
||||
* Validates a date is after another one
|
||||
*
|
||||
* @param source source date to compare
|
||||
* @param target target date to compare
|
||||
* @returns `true` if the source date is after the target one, otherwise `false`
|
||||
|
@@ -18,7 +18,6 @@
|
||||
import { ObjectUtils } from './object-utils';
|
||||
|
||||
describe('ObjectUtils', () => {
|
||||
|
||||
it('should get top level property value', () => {
|
||||
const obj = {
|
||||
id: 1
|
||||
|
@@ -19,13 +19,11 @@ export class ObjectUtils {
|
||||
/**
|
||||
* Gets a value from an object by composed key
|
||||
* ObjectUtils.getValue({ item: { nodeType: 'cm:folder' }}, 'item.nodeType') ==> 'cm:folder'
|
||||
*
|
||||
* @param target target object
|
||||
* @param key object property key
|
||||
* @returns object property value
|
||||
*/
|
||||
static getValue(target: any, key: string): any {
|
||||
|
||||
if (!target || !key) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -80,46 +78,38 @@ export class ObjectUtils {
|
||||
}
|
||||
|
||||
static isBooleanObject(target: any): boolean {
|
||||
return Object.values(target).every(value => typeof value === 'boolean');
|
||||
return Object.values(target).every((value) => typeof value === 'boolean');
|
||||
}
|
||||
|
||||
static booleanPrettify(target: any, enhancer?: (param: string) => string): string {
|
||||
|
||||
if (
|
||||
!target ||
|
||||
ObjectUtils.isEmpty(target) ||
|
||||
!ObjectUtils.isBooleanObject(target)
|
||||
) {
|
||||
if (!target || ObjectUtils.isEmpty(target) || !ObjectUtils.isBooleanObject(target)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (
|
||||
!ObjectUtils.isObject(target) ||
|
||||
!ObjectUtils.hasKeys(target)
|
||||
) {
|
||||
if (!ObjectUtils.isObject(target) || !ObjectUtils.hasKeys(target)) {
|
||||
return target.toString();
|
||||
}
|
||||
|
||||
const greenBorderWhiteCheckSymbol = '✅';
|
||||
const redCrossSymbol = '❌';
|
||||
|
||||
target = Object.keys(target).map((key) => {
|
||||
if (target[key]) {
|
||||
if (enhancer) {
|
||||
return `${greenBorderWhiteCheckSymbol} ${enhancer(key)}`;
|
||||
} else {
|
||||
return `${greenBorderWhiteCheckSymbol} ${key}`;
|
||||
target = Object.keys(target)
|
||||
.map((key) => {
|
||||
if (target[key]) {
|
||||
if (enhancer) {
|
||||
return `${greenBorderWhiteCheckSymbol} ${enhancer(key)}`;
|
||||
} else {
|
||||
return `${greenBorderWhiteCheckSymbol} ${key}`;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (enhancer) {
|
||||
return `${redCrossSymbol} ${enhancer(key)}`;
|
||||
} else {
|
||||
return `${redCrossSymbol} ${key}`;
|
||||
}
|
||||
|
||||
}).join('\n');
|
||||
if (enhancer) {
|
||||
return `${redCrossSymbol} ${enhancer(key)}`;
|
||||
} else {
|
||||
return `${redCrossSymbol} ${key}`;
|
||||
}
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
return target;
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@
|
||||
import { ObjectUtils } from './object-utils';
|
||||
|
||||
export class StringUtils {
|
||||
|
||||
static capitalize(target: string): string {
|
||||
return target.charAt(0).toUpperCase() + target.slice(1).toLowerCase();
|
||||
}
|
||||
@@ -37,7 +36,7 @@ export class StringUtils {
|
||||
|
||||
static removeAll(target: string, ...delimiters: string[]): string {
|
||||
const delimiterObj = {};
|
||||
delimiters.forEach(delimiter => {
|
||||
delimiters.forEach((delimiter) => {
|
||||
delimiterObj[delimiter] = '';
|
||||
});
|
||||
|
||||
@@ -49,8 +48,6 @@ export class StringUtils {
|
||||
const bagOfWords = redactedTarget.split(' ');
|
||||
const capitalizedBagOfWords = bagOfWords.map((word) => StringUtils.capitalize(word));
|
||||
|
||||
|
||||
return capitalizedBagOfWords.join(' ');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -15,32 +15,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
state,
|
||||
style,
|
||||
animate,
|
||||
transition,
|
||||
query,
|
||||
group,
|
||||
sequence,
|
||||
AnimationStateMetadata,
|
||||
AnimationTransitionMetadata
|
||||
} from '@angular/animations';
|
||||
import { state, style, animate, transition, query, group, sequence, AnimationStateMetadata, AnimationTransitionMetadata } from '@angular/animations';
|
||||
|
||||
export const contextMenuAnimation: ( AnimationStateMetadata | AnimationTransitionMetadata)[] = [
|
||||
state('void', style({
|
||||
opacity: 0,
|
||||
transform: 'scale(0.01, 0.01)'
|
||||
})),
|
||||
transition('void => *', sequence([
|
||||
query('.mat-mdc-menu-content', style({ opacity: 0 })),
|
||||
animate('100ms linear', style({ opacity: 1, transform: 'scale(1, 0.5)' })),
|
||||
group([
|
||||
query('.mat-mdc-menu-content', animate('400ms cubic-bezier(0.55, 0, 0.55, 0.2)',
|
||||
style({ opacity: 1 })
|
||||
)),
|
||||
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({ transform: 'scale(1, 1)' }))
|
||||
export const contextMenuAnimation: (AnimationStateMetadata | AnimationTransitionMetadata)[] = [
|
||||
state(
|
||||
'void',
|
||||
style({
|
||||
opacity: 0,
|
||||
transform: 'scale(0.01, 0.01)'
|
||||
})
|
||||
),
|
||||
transition(
|
||||
'void => *',
|
||||
sequence([
|
||||
query('.mat-mdc-menu-content', style({ opacity: 0 })),
|
||||
animate('100ms linear', style({ opacity: 1, transform: 'scale(1, 0.5)' })),
|
||||
group([
|
||||
query('.mat-mdc-menu-content', animate('400ms cubic-bezier(0.55, 0, 0.55, 0.2)', style({ opacity: 1 }))),
|
||||
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({ transform: 'scale(1, 1)' }))
|
||||
])
|
||||
])
|
||||
])),
|
||||
),
|
||||
transition('* => void', animate('150ms 50ms linear', style({ opacity: 0 })))
|
||||
];
|
||||
|
@@ -33,11 +33,7 @@ const DEFAULT_CONFIG: ContextMenuOverlayConfig = {
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ContextMenuOverlayService {
|
||||
|
||||
constructor(
|
||||
private injector: Injector,
|
||||
private overlay: Overlay
|
||||
) {}
|
||||
constructor(private injector: Injector, private overlay: Overlay) {}
|
||||
|
||||
open(config: ContextMenuOverlayConfig): ContextMenuOverlayRef {
|
||||
const overlayConfig = { ...DEFAULT_CONFIG, ...config };
|
||||
@@ -53,12 +49,15 @@ export class ContextMenuOverlayService {
|
||||
// prevent native contextmenu on overlay element if config.hasBackdrop is true
|
||||
if (overlayConfig.hasBackdrop) {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
(overlay as any)._backdropElement
|
||||
.addEventListener('contextmenu', (event) => {
|
||||
(overlay as any)._backdropElement.addEventListener(
|
||||
'contextmenu',
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
(overlay as any)._backdropClick.next(null);
|
||||
}, true);
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return overlayRef;
|
||||
@@ -88,28 +87,31 @@ export class ContextMenuOverlayService {
|
||||
}
|
||||
|
||||
private getOverlayConfig(config: ContextMenuOverlayConfig): OverlayConfig {
|
||||
const { clientY, clientX } = config.source;
|
||||
const { clientY, clientX } = config.source;
|
||||
|
||||
const fakeElement: any = {
|
||||
getBoundingClientRect: (): ClientRect => ({
|
||||
bottom: clientY,
|
||||
height: 0,
|
||||
left: clientX,
|
||||
right: clientX,
|
||||
top: clientY,
|
||||
width: 0
|
||||
} as any)
|
||||
getBoundingClientRect: (): ClientRect =>
|
||||
({
|
||||
bottom: clientY,
|
||||
height: 0,
|
||||
left: clientX,
|
||||
right: clientX,
|
||||
top: clientY,
|
||||
width: 0
|
||||
} as any)
|
||||
};
|
||||
|
||||
const positionStrategy = this.overlay
|
||||
.position()
|
||||
.flexibleConnectedTo(new ElementRef(fakeElement))
|
||||
.withPositions([{
|
||||
originX: 'start',
|
||||
originY: 'bottom',
|
||||
overlayX: 'start',
|
||||
overlayY: 'top'
|
||||
}]);
|
||||
.withPositions([
|
||||
{
|
||||
originX: 'start',
|
||||
originY: 'bottom',
|
||||
overlayX: 'start',
|
||||
overlayY: 'top'
|
||||
}
|
||||
]);
|
||||
|
||||
const overlayConfig = new OverlayConfig({
|
||||
hasBackdrop: config.hasBackdrop,
|
||||
|
@@ -18,8 +18,7 @@
|
||||
import { OverlayRef } from '@angular/cdk/overlay';
|
||||
|
||||
export class ContextMenuOverlayRef {
|
||||
|
||||
constructor(private overlayRef: OverlayRef) { }
|
||||
constructor(private overlayRef: OverlayRef) {}
|
||||
|
||||
close(): void {
|
||||
this.overlayRef.dispose();
|
||||
|
@@ -20,7 +20,6 @@ import { DataColumn } from '../data/data-column.model';
|
||||
import { DataRow } from '../data/data-row.model';
|
||||
|
||||
export class DataCellEventModel {
|
||||
|
||||
readonly row: DataRow;
|
||||
readonly col: DataColumn;
|
||||
actions: any[];
|
||||
@@ -30,14 +29,11 @@ export class DataCellEventModel {
|
||||
this.col = col;
|
||||
this.actions = actions || [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class DataCellEvent extends BaseEvent<DataCellEventModel> {
|
||||
|
||||
constructor(row: DataRow, col: DataColumn, actions: any[]) {
|
||||
super();
|
||||
this.value = new DataCellEventModel(row, col, actions);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -19,7 +19,6 @@ import { BaseEvent } from '../../events';
|
||||
import { DataRow } from '../data/data-row.model';
|
||||
|
||||
export class DataRowActionModel {
|
||||
|
||||
row: DataRow;
|
||||
action: any;
|
||||
|
||||
@@ -30,7 +29,6 @@ export class DataRowActionModel {
|
||||
}
|
||||
|
||||
export class DataRowActionEvent extends BaseEvent<DataRowActionModel> {
|
||||
|
||||
// backwards compatibility with 1.2.0 and earlier
|
||||
get args(): DataRowActionModel {
|
||||
return this.value;
|
||||
@@ -40,5 +38,4 @@ export class DataRowActionEvent extends BaseEvent<DataRowActionModel> {
|
||||
super();
|
||||
this.value = new DataRowActionModel(row, action);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -32,7 +32,6 @@ import { LocalizedDatePipe, TimeAgoPipe } from '../../../pipes';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DateCellComponent extends DataTableCellComponent implements OnInit {
|
||||
|
||||
@Input()
|
||||
dateConfig: DateConfig;
|
||||
|
||||
|
@@ -22,11 +22,12 @@ export const mockCarsData: any = [
|
||||
{
|
||||
car_id: 1,
|
||||
car_name: 'Fiat 126p (Process)',
|
||||
car_price: 599.00,
|
||||
car_price: 599.0,
|
||||
fuel_consumption: 5.25789,
|
||||
is_available: 'false',
|
||||
production_start: '1972-04-23',
|
||||
description: 'The Fiat 126 (Type 126) is a four-passenger, rear-engine, city car manufactured and marketed by Fiat over a twenty-eight year production run from 1972 until 2000, over a single generation.',
|
||||
description:
|
||||
'The Fiat 126 (Type 126) is a four-passenger, rear-engine, city car manufactured and marketed by Fiat over a twenty-eight year production run from 1972 until 2000, over a single generation.',
|
||||
icon: 'airport_shuttle',
|
||||
wikipedia_link: 'https://en.wikipedia.org/wiki/Fiat_126'
|
||||
},
|
||||
@@ -48,7 +49,8 @@ export const mockCarsData: any = [
|
||||
fuel_consumption: 6,
|
||||
is_available: 'true',
|
||||
production_start: '1998-06-25T12:25:20',
|
||||
description: 'The Audi A3 is a subcompact executive/small family car (C-segment) manufactured and marketed by the German automaker Audi AG since September 1996, currently in its fourth generation.',
|
||||
description:
|
||||
'The Audi A3 is a subcompact executive/small family car (C-segment) manufactured and marketed by the German automaker Audi AG since September 1996, currently in its fourth generation.',
|
||||
icon: 'directions_car',
|
||||
wikipedia_link: 'https://en.wikipedia.org/wiki/Audi_A3'
|
||||
}
|
||||
|
@@ -15,13 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ViewEncapsulation,
|
||||
Input,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, ViewEncapsulation, Input, OnInit } from '@angular/core';
|
||||
import { DataTableCellComponent } from '../datatable-cell/datatable-cell.component';
|
||||
import { DecimalConfig } from '../../data/data-column.model';
|
||||
import { CommonModule } from '@angular/common';
|
||||
@@ -36,7 +30,6 @@ import { CommonModule } from '@angular/common';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class NumberCellComponent extends DataTableCellComponent implements OnInit {
|
||||
|
||||
@Input()
|
||||
decimalConfig: DecimalConfig;
|
||||
|
||||
|
@@ -19,7 +19,6 @@ import { BaseUIEvent } from '../../events';
|
||||
import { DataRow } from './data-row.model';
|
||||
|
||||
export class DataRowEvent extends BaseUIEvent<DataRow> {
|
||||
|
||||
sender: any;
|
||||
|
||||
constructor(value: DataRow, domEvent: Event, sender?: any) {
|
||||
@@ -28,5 +27,4 @@ export class DataRowEvent extends BaseUIEvent<DataRow> {
|
||||
this.event = domEvent;
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -16,10 +16,5 @@
|
||||
*/
|
||||
|
||||
export class DataSorting {
|
||||
constructor(
|
||||
public key?: string,
|
||||
public direction?: string,
|
||||
public options?: Intl.CollatorOptions
|
||||
) {
|
||||
}
|
||||
constructor(public key?: string, public direction?: string, public options?: Intl.CollatorOptions) {}
|
||||
}
|
||||
|
@@ -24,14 +24,7 @@ import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
@NgModule({
|
||||
declarations: [EditJsonDialogComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
TranslateModule,
|
||||
MatDialogModule,
|
||||
MatButtonModule
|
||||
],
|
||||
imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, MatDialogModule, MatButtonModule],
|
||||
exports: [EditJsonDialogComponent]
|
||||
})
|
||||
export class EditJsonDialogModule {}
|
||||
|
@@ -17,10 +17,7 @@
|
||||
|
||||
import { Component, OnInit, OnChanges, Input } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import {
|
||||
EditJsonDialogComponent,
|
||||
EditJsonDialogSettings
|
||||
} from './edit-json.dialog';
|
||||
import { EditJsonDialogComponent, EditJsonDialogSettings } from './edit-json.dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-edit-json-dialog-storybook',
|
||||
@@ -75,11 +72,7 @@ export class EditJsonDialogStorybookComponent implements OnInit, OnChanges {
|
||||
.afterClosed()
|
||||
.subscribe((value: string) => {
|
||||
if (value) {
|
||||
this._settings.value = JSON.stringify(
|
||||
JSON.parse(value),
|
||||
null,
|
||||
' '
|
||||
);
|
||||
this._settings.value = JSON.stringify(JSON.parse(value), null, ' ');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -31,16 +31,13 @@ export interface EditJsonDialogSettings {
|
||||
host: { class: 'adf-edit-json-dialog' }
|
||||
})
|
||||
export class EditJsonDialogComponent implements OnInit {
|
||||
|
||||
editable: boolean = false;
|
||||
title: string = 'JSON';
|
||||
|
||||
@Input()
|
||||
value: string = '';
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) private settings: EditJsonDialogSettings
|
||||
) {}
|
||||
constructor(@Inject(MAT_DIALOG_DATA) private settings: EditJsonDialogSettings) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.settings) {
|
||||
|
@@ -60,7 +60,6 @@ export class UnsavedChangesDialogComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* Sets 'unsaved_changes__modal_visible' checked state (true or false string) as new item in local storage.
|
||||
*
|
||||
* @param savePreferences - MatCheckboxChange object with information about checkbox state.
|
||||
*/
|
||||
onToggleCheckboxPreferences(savePreferences: MatCheckboxChange) {
|
||||
|
@@ -38,7 +38,6 @@ export class UnsavedChangesGuard implements CanDeactivate<any> {
|
||||
|
||||
/**
|
||||
* Allows to deactivate route when there is no unsaved changes, otherwise displays dialog to confirm discarding changes.
|
||||
*
|
||||
* @returns boolean | Observable<boolean> true when there is no unsaved changes or changes can be discarded, false otherwise.
|
||||
*/
|
||||
canDeactivate(): boolean | Observable<boolean> {
|
||||
|
@@ -20,7 +20,6 @@ import { fakeAsync, tick } from '@angular/core/testing';
|
||||
import { UploadDirective } from './upload.directive';
|
||||
|
||||
describe('UploadDirective', () => {
|
||||
|
||||
let directive: UploadDirective;
|
||||
let nativeElement: any;
|
||||
|
||||
@@ -139,7 +138,7 @@ describe('UploadDirective', () => {
|
||||
directive.enabled = true;
|
||||
directive.mode = ['click'];
|
||||
const files = [{}];
|
||||
const event = {currentTarget: {files}, target: {value: '/testpath/document.pdf'}};
|
||||
const event = { currentTarget: { files }, target: { value: '/testpath/document.pdf' } };
|
||||
|
||||
directive.onSelectFiles(event);
|
||||
expect(event.target.value).toBe('');
|
||||
|
@@ -191,7 +191,6 @@ export class UploadDirective implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* Extract files from the DataTransfer object used to hold the data that is being dragged during a drag and drop operation.
|
||||
*
|
||||
* @param dataTransfer DataTransfer object
|
||||
* @returns a list of file info objects
|
||||
*/
|
||||
@@ -252,7 +251,6 @@ export class UploadDirective implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* Invoked when user selects files or folders by means of File Dialog
|
||||
*
|
||||
* @param event DOM event
|
||||
*/
|
||||
onSelectFiles(event: any): void {
|
||||
|
@@ -46,7 +46,6 @@ describe('DynamicChipListComponent', () => {
|
||||
|
||||
/**
|
||||
* Find 'More' button
|
||||
*
|
||||
* @returns native element
|
||||
*/
|
||||
function findViewMoreButton(): HTMLButtonElement {
|
||||
@@ -55,7 +54,6 @@ describe('DynamicChipListComponent', () => {
|
||||
|
||||
/**
|
||||
* Get the chips
|
||||
*
|
||||
* @returns native element list
|
||||
*/
|
||||
function findChips(): NodeListOf<Element> {
|
||||
@@ -176,7 +174,6 @@ describe('DynamicChipListComponent', () => {
|
||||
|
||||
/**
|
||||
* Render chips
|
||||
*
|
||||
* @param chipsToRender chips to render
|
||||
*/
|
||||
async function renderChips(chipsToRender?: Chip[]) {
|
||||
|
@@ -17,7 +17,6 @@
|
||||
|
||||
/** Base cancellable event implementation */
|
||||
export class BaseEvent<T> {
|
||||
|
||||
private isDefaultPrevented: boolean = false;
|
||||
|
||||
value: T;
|
||||
@@ -29,5 +28,4 @@ export class BaseEvent<T> {
|
||||
preventDefault() {
|
||||
this.isDefaultPrevented = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -185,7 +185,6 @@ export abstract class FormBaseComponent {
|
||||
|
||||
/**
|
||||
* Invoked when user clicks outcome button.
|
||||
*
|
||||
* @param outcome Form outcome model
|
||||
* @returns `true` if outcome button was clicked, otherwise `false`
|
||||
*/
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user