From 18d6a9ec8e4e90ebf7840e368010a501b9e4fda4 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 5 Aug 2020 14:05:58 +0300 Subject: [PATCH] refactor: improve code readability --- .../packages/core/src/lib/core.module.ts | 7 +- .../core/src/lib/tests/initial-utils.spec.ts | 22 +-- .../src/lib/tests/multi-tenancy-utils.spec.ts | 18 +- .../utils/formatted-string-value-extractor.ts | 156 ------------------ .../core/src/lib/utils/initial-utils.ts | 10 -- .../core/src/lib/utils/multi-tenancy-utils.ts | 23 +-- 6 files changed, 28 insertions(+), 208 deletions(-) delete mode 100644 npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index 16295b5abf..85cf87297f 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -21,6 +21,7 @@ import { PermissionDirective } from './directives/permission.directive'; import { ReplaceableTemplateDirective } from './directives/replaceable-template.directive'; import { StopPropagationDirective } from './directives/stop-propagation.directive'; import { VisibilityDirective } from './directives/visibility.directive'; +import { OAuthConfigurationHandler } from './handlers/oauth-configuration.handler'; import { RoutesHandler } from './handlers/routes.handler'; import { ApiInterceptor } from './interceptors/api.interceptor'; import { LocalizationModule } from './localization.module'; @@ -37,7 +38,7 @@ import { SessionState } from './states/session.state'; import { coreOptionsFactory, CORE_OPTIONS } from './tokens/options.token'; import { noop } from './utils/common-utils'; import './utils/date-extensions'; -import { configureOAuth, getInitialData, localeInitializer } from './utils/initial-utils'; +import { getInitialData, localeInitializer } from './utils/initial-utils'; export function storageFactory(): OAuthStorage { return localStorage; @@ -187,8 +188,8 @@ export class CoreModule { { provide: APP_INITIALIZER, multi: true, - deps: [Injector, NGXS_CONFIG_PLUGIN_OPTIONS], - useFactory: configureOAuth, + deps: [OAuthConfigurationHandler], + useFactory: noop, }, { provide: APP_INITIALIZER, diff --git a/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts index f1417eae2f..ae9ce94650 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts @@ -1,10 +1,11 @@ import { Component, Injector } from '@angular/core'; import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; import { Store } from '@ngxs/store'; +import { OAuthService } from 'angular-oauth2-oidc'; import { of } from 'rxjs'; import { GetAppConfiguration } from '../actions'; -import { getInitialData, localeInitializer, configureOAuth, checkAccessToken } from '../utils'; -import { OAuthService } from 'angular-oauth2-oidc'; +import { CORE_OPTIONS } from '../tokens/options.token'; +import { checkAccessToken, getInitialData, localeInitializer } from '../utils'; import * as multiTenancyUtils from '../utils/multi-tenancy-utils'; @Component({ @@ -18,24 +19,13 @@ describe('InitialUtils', () => { const createComponent = createComponentFactory({ component: DummyComponent, mocks: [Store, OAuthService], + providers: [ + { provide: CORE_OPTIONS, useValue: { environment: { oAuthConfig: { issuer: 'test' } } } }, + ], }); beforeEach(() => (spectator = createComponent())); - describe('#configureOAuth', () => { - test('should be called the the configure method of OAuthService', async () => { - const injector = spectator.inject(Injector); - const injectorSpy = jest.spyOn(injector, 'get'); - const oAuth = spectator.inject(OAuthService); - const configureSpy = jest.spyOn(oAuth, 'configure'); - - injectorSpy.mockReturnValueOnce(oAuth); - - await configureOAuth(injector, { environment: { oAuthConfig: { issuer: 'test' } } })(); - expect(configureSpy).toHaveBeenCalledWith({ issuer: 'test' }); - }); - }); - describe('#getInitialData', () => { test('should dispatch GetAppConfiguration and return', async () => { const injector = spectator.inject(Injector); diff --git a/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts index bfff03f7e6..6d8b3d6941 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts @@ -1,12 +1,11 @@ import { Component, Injector } from '@angular/core'; import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; import { Store } from '@ngxs/store'; -import { MultiTenancyService } from '../services/multi-tenancy.service'; -import { parseTenantFromUrl, getCurrentTenancyNameOrNull } from '../utils'; -import * as multiTenancyUtils from '../utils/multi-tenancy-utils'; -import { of, Subject, BehaviorSubject } from 'rxjs'; -import { FindTenantResultDto } from '../models/find-tenant-result-dto'; import clone from 'just-clone'; +import { BehaviorSubject } from 'rxjs'; +import { FindTenantResultDto } from '../models/find-tenant-result-dto'; +import { MultiTenancyService } from '../services/multi-tenancy.service'; +import { getCurrentTenancyName, parseTenantFromUrl } from '../utils'; const environment = { production: false, @@ -59,16 +58,17 @@ describe('MultiTenancyUtils', () => { beforeEach(() => (spectator = createComponent())); - describe('#getCurrentTenancyNameOrNull', () => { + describe('#getCurrentTenancyName', () => { test('should get tenancy name from href', async () => { setHref('https://abp.volosoft.com/'); - expect(getCurrentTenancyNameOrNull('https://{0}.volosoft.com')).toBe('abp'); + expect(getCurrentTenancyName('https://{0}.volosoft.com')).toBe('abp'); setHref('https://volosoft.com/'); - expect(getCurrentTenancyNameOrNull('https://{0}.com')).toBe('volosoft'); + expect(getCurrentTenancyName('https://{0}.com')).toBe('volosoft'); setHref('https://volosoft.com/abp/'); - expect(getCurrentTenancyNameOrNull('https://volosoft.com/{0}')).toBe('abp'); + expect(getCurrentTenancyName('https://volosoft.com/{0}')).toBe('abp'); + expect(getCurrentTenancyName('https://volosoft.com')).toBe(undefined); }); }); diff --git a/npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts b/npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts deleted file mode 100644 index 7e9e3f00da..0000000000 --- a/npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts +++ /dev/null @@ -1,156 +0,0 @@ -class ExtractionResult { - public isMatch: boolean; - public matches: any[]; - - constructor(isMatch: boolean) { - this.isMatch = isMatch; - this.matches = []; - } -} - -enum FormatStringTokenType { - ConstantText, - DynamicValue, -} - -class FormatStringToken { - public text: string; - public type: FormatStringTokenType; - - constructor(text: string, type: FormatStringTokenType) { - this.text = text; - this.type = type; - } -} - -class FormatStringTokenizer { - tokenize(format: string, includeBracketsForDynamicValues: boolean = false): FormatStringToken[] { - const tokens: FormatStringToken[] = []; - - let currentText = ''; - let inDynamicValue = false; - - for (let i = 0; i < format.length; i++) { - const c = format[i]; - switch (c) { - case '{': - if (inDynamicValue) { - throw new Error( - 'Incorrect syntax at char ' + - i + - '! format string can not contain nested dynamic value expression!', - ); - } - - inDynamicValue = true; - - if (currentText.length > 0) { - tokens.push(new FormatStringToken(currentText, FormatStringTokenType.ConstantText)); - currentText = ''; - } - - break; - case '}': - if (!inDynamicValue) { - throw new Error( - 'Incorrect syntax at char ' + - i + - '! These is no opening brackets for the closing bracket }.', - ); - } - - inDynamicValue = false; - - if (currentText.length <= 0) { - throw new Error( - 'Incorrect syntax at char ' + i + '! Brackets does not containt any chars.', - ); - } - - let dynamicValue = currentText; - if (includeBracketsForDynamicValues) { - dynamicValue = '{' + dynamicValue + '}'; - } - - tokens.push(new FormatStringToken(dynamicValue, FormatStringTokenType.DynamicValue)); - currentText = ''; - - break; - default: - currentText += c; - break; - } - } - - if (inDynamicValue) { - throw new Error('There is no closing } char for an opened { char.'); - } - - if (currentText.length > 0) { - tokens.push(new FormatStringToken(currentText, FormatStringTokenType.ConstantText)); - } - - return tokens; - } -} - -export class FormattedStringValueExtractor { - extract(str: string, format: string): ExtractionResult { - if (str === format) { - return new ExtractionResult(true); - } - - const formatTokens = new FormatStringTokenizer().tokenize(format); - if (!formatTokens) { - return new ExtractionResult(str === ''); - } - - const result = new ExtractionResult(true); - - for (let i = 0; i < formatTokens.length; i++) { - const currentToken = formatTokens[i]; - const previousToken = i > 0 ? formatTokens[i - 1] : null; - - if (currentToken.type === FormatStringTokenType.ConstantText) { - if (i === 0) { - if (str.indexOf(currentToken.text) !== 0) { - result.isMatch = false; - return result; - } - - str = str.substr(currentToken.text.length, str.length - currentToken.text.length); - } else { - const matchIndex = str.indexOf(currentToken.text); - if (matchIndex < 0) { - result.isMatch = false; - return result; - } - - result.matches.push({ name: previousToken.text, value: str.substr(0, matchIndex) }); - str = str.substring(0, matchIndex + currentToken.text.length); - } - } - } - - const lastToken = formatTokens[formatTokens.length - 1]; - if (lastToken.type === FormatStringTokenType.DynamicValue) { - result.matches.push({ name: lastToken.text, value: str }); - } - - return result; - } - - isMatch(str: string, format: string): string[] { - const result = new FormattedStringValueExtractor().extract(str, format); - if (!result.isMatch) { - return []; - } - - const values = []; - for (let i = 0; i < result.matches.length; i++) { - values.push(result.matches[i].value); - } - - return values; - } -} diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index d9c8ae163b..b0adfd4980 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -9,16 +9,6 @@ import { ConfigState } from '../states/config.state'; import { CORE_OPTIONS } from '../tokens/options.token'; import { parseTenantFromUrl } from './multi-tenancy-utils'; -export function configureOAuth(injector: Injector, options: ABP.Root) { - const fn = () => { - const oAuth = injector.get(OAuthService); - oAuth.configure(options.environment.oAuthConfig); - return Promise.resolve(); - }; - - return fn; -} - export function getInitialData(injector: Injector) { const fn = async () => { const store: Store = injector.get(Store); diff --git a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts index 58801fbcb3..fae20ef614 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts @@ -5,24 +5,17 @@ import { SetEnvironment } from '../actions'; import { Config } from '../models/config'; import { MultiTenancyService } from '../services/multi-tenancy.service'; import { ConfigState } from '../states/config.state'; -import { FormattedStringValueExtractor } from './formatted-string-value-extractor'; +import clone from 'just-clone'; const tenancyPlaceholder = '{0}'; -export function getCurrentTenancyNameOrNull(appBaseUrl: string): string { - if (appBaseUrl.indexOf(tenancyPlaceholder) < 0) return null; - +export function getCurrentTenancyName(appBaseUrl: string): string { if (appBaseUrl.charAt(appBaseUrl.length - 1) !== '/') appBaseUrl += '/'; const currentRootAddress = window.location.href; - const formattedStringValueExtractor = new FormattedStringValueExtractor(); - const values = formattedStringValueExtractor.isMatch(currentRootAddress, appBaseUrl); - if (!values.length) { - return null; - } - - return values[0]; + const regex = appBaseUrl.replace(/\./g, '.').replace(tenancyPlaceholder, '(.+)'); + return (currentRootAddress.match(regex) || []).slice(1)[0]; } export async function parseTenantFromUrl(injector: Injector) { @@ -31,7 +24,7 @@ export async function parseTenantFromUrl(injector: Injector) { const environment = store.selectSnapshot(ConfigState.getOne('environment')) as Config.Environment; const { baseUrl = '' } = environment.application; - const tenancyName = getCurrentTenancyNameOrNull(baseUrl); + const tenancyName = getCurrentTenancyName(baseUrl); if (tenancyName) { multiTenancyService.isTenantBoxVisible = false; @@ -51,8 +44,10 @@ export async function parseTenantFromUrl(injector: Injector) { return Promise.resolve(); } -export function setEnvironment(store: Store, tenancyName: string) { - const environment = store.selectSnapshot(ConfigState.getOne('environment')) as Config.Environment; +function setEnvironment(store: Store, tenancyName: string) { + const environment = clone( + store.selectSnapshot(ConfigState.getOne('environment')), + ) as Config.Environment; if (environment.application.baseUrl) { environment.application.baseUrl = environment.application.baseUrl.replace(