mirror of https://github.com/abpframework/abp
parent
70308947b6
commit
57cd025ba5
@ -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