mirror of https://github.com/abpframework/abp.git
8 changed files with 254 additions and 3 deletions
@ -0,0 +1,16 @@ |
|||||
|
|
||||
|
export class FindTenantResultDto { |
||||
|
success: boolean; |
||||
|
tenantId?: string; |
||||
|
name: string; |
||||
|
|
||||
|
constructor(initialValues: Partial<FindTenantResultDto> = {}) { |
||||
|
if (initialValues) { |
||||
|
for (const key in initialValues) { |
||||
|
if (initialValues.hasOwnProperty(key)) { |
||||
|
this[key] = initialValues[key]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,156 @@ |
|||||
|
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; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,73 @@ |
|||||
|
import { Injector } from '@angular/core'; |
||||
|
import { Store } from '@ngxs/store'; |
||||
|
import { ConfigState } from '../states/config.state'; |
||||
|
import { Config } from '../models/config'; |
||||
|
import { FormattedStringValueExtractor } from './formatted-string-value-extractor'; |
||||
|
import { MultiTenancyService } from '../services/multi-tenancy.service'; |
||||
|
import { tap, switchMap } from 'rxjs/operators'; |
||||
|
import { SetTenant, SetEnvironment } from '../actions'; |
||||
|
import { of } from 'rxjs'; |
||||
|
|
||||
|
const tenancyPlaceholder = '{TENANCY_NAME}'; |
||||
|
|
||||
|
export function getCurrentTenancyNameOrNull(appBaseUrl: string): string { |
||||
|
if (appBaseUrl.indexOf(tenancyPlaceholder) < 0) return null; |
||||
|
|
||||
|
const currentRootAddress = document.location.href; |
||||
|
|
||||
|
const formattedStringValueExtracter = new FormattedStringValueExtractor(); |
||||
|
const values: any[] = formattedStringValueExtracter.isMatch(currentRootAddress, appBaseUrl); |
||||
|
if (!values.length) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return values[0]; |
||||
|
} |
||||
|
|
||||
|
export async function parseTenantFromUrl(injector: Injector) { |
||||
|
const store: Store = injector.get(Store); |
||||
|
const multiTenancyService = injector.get(MultiTenancyService); |
||||
|
const environment = store.selectSnapshot(ConfigState.getOne('environment')) as Config.Environment; |
||||
|
|
||||
|
const { baseUrl = '' } = environment.application; |
||||
|
const tenancyName = getCurrentTenancyNameOrNull(baseUrl); |
||||
|
|
||||
|
if (tenancyName) { |
||||
|
multiTenancyService.isTenantBoxVisible = false; |
||||
|
|
||||
|
return setEnvironment(store, tenancyName) |
||||
|
.pipe( |
||||
|
switchMap(() => multiTenancyService.findTenantByName(tenancyName, { __tenant: '' })), |
||||
|
tap(res => { |
||||
|
if (!res.success) return; |
||||
|
const tenant = { id: res.tenantId, name: res.name }; |
||||
|
multiTenancyService.domainTenant = tenant; |
||||
|
}), |
||||
|
) |
||||
|
.toPromise(); |
||||
|
} |
||||
|
|
||||
|
return Promise.resolve(); |
||||
|
} |
||||
|
|
||||
|
export function setEnvironment(store: Store, tenancyName: string) { |
||||
|
const environment = store.selectSnapshot(ConfigState.getOne('environment')) as Config.Environment; |
||||
|
|
||||
|
if (environment.application.baseUrl) { |
||||
|
environment.application.baseUrl = environment.application.baseUrl.replace( |
||||
|
tenancyPlaceholder, |
||||
|
tenancyName, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Object.keys(environment.apis).forEach(api => { |
||||
|
Object.keys(environment.apis[api]).forEach(key => { |
||||
|
environment.apis[api][key] = environment.apis[api][key].replace( |
||||
|
tenancyPlaceholder, |
||||
|
tenancyName, |
||||
|
); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
return store.dispatch(new SetEnvironment(environment)); |
||||
|
} |
||||
Loading…
Reference in new issue