fix: prefer primary Tenant.domain in get_user/get_version matching
When multiple tenants claim the same host via domains aliases, resolve the tenant whose primary domain matches first so branding edits apply to the expected version. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -17,7 +17,7 @@ export class GetUserService {
|
|||||||
where: { isActive: true },
|
where: { isActive: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
const tenant = tenants.find((item) => this.matchesHost(item, host));
|
const tenant = this.findTenantForHost(tenants, host);
|
||||||
if (!tenant) {
|
if (!tenant) {
|
||||||
throw new NotFoundException('tenant not found for domain');
|
throw new NotFoundException('tenant not found for domain');
|
||||||
}
|
}
|
||||||
@@ -181,6 +181,46 @@ export class GetUserService {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* اول دامنهٔ اصلی (Tenant.domain)، بعد aliases داخل domains[].
|
||||||
|
* اگر چند نسخه یک دامنه را داشته باشند، نسخهٔ primary برنده است.
|
||||||
|
*/
|
||||||
|
private findTenantForHost<
|
||||||
|
T extends {
|
||||||
|
domain: string;
|
||||||
|
domains: unknown;
|
||||||
|
},
|
||||||
|
>(tenants: T[], host: string): T | undefined {
|
||||||
|
const normalizedHost = this.normalizeHost(host);
|
||||||
|
const hostNoWww = normalizedHost.replace(/^www\./, '');
|
||||||
|
|
||||||
|
const primary = tenants.find((item) => {
|
||||||
|
const d = this.normalizeHost(item.domain);
|
||||||
|
return d === normalizedHost || d.replace(/^www\./, '') === hostNoWww;
|
||||||
|
});
|
||||||
|
if (primary) return primary;
|
||||||
|
|
||||||
|
return tenants.find((item) => this.matchesAliasHost(item, normalizedHost));
|
||||||
|
}
|
||||||
|
|
||||||
|
private matchesAliasHost(
|
||||||
|
tenant: {
|
||||||
|
domain: string;
|
||||||
|
domains: unknown;
|
||||||
|
},
|
||||||
|
host: string,
|
||||||
|
) {
|
||||||
|
const hostNoWww = host.replace(/^www\./, '');
|
||||||
|
for (const value of this.readDomains(tenant.domains)) {
|
||||||
|
const normalized = this.normalizeHost(value);
|
||||||
|
if (!normalized) continue;
|
||||||
|
if (normalized === host || normalized.replace(/^www\./, '') === hostNoWww) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private matchesHost(
|
private matchesHost(
|
||||||
tenant: {
|
tenant: {
|
||||||
domain: string;
|
domain: string;
|
||||||
@@ -188,15 +228,7 @@ export class GetUserService {
|
|||||||
},
|
},
|
||||||
host: string,
|
host: string,
|
||||||
) {
|
) {
|
||||||
const candidates = new Set<string>();
|
return Boolean(this.findTenantForHost([tenant], host));
|
||||||
for (const value of [tenant.domain, ...this.readDomains(tenant.domains)]) {
|
|
||||||
const normalized = this.normalizeHost(value);
|
|
||||||
if (!normalized) continue;
|
|
||||||
candidates.add(normalized);
|
|
||||||
candidates.add(normalized.replace(/^www\./, ''));
|
|
||||||
candidates.add(`www.${normalized.replace(/^www\./, '')}`);
|
|
||||||
}
|
|
||||||
return candidates.has(host) || candidates.has(host.replace(/^www\./, ''));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readDomains(raw: unknown): string[] {
|
private readDomains(raw: unknown): string[] {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export class GetVersionService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const tenant = tenants.find((item) => this.matchesHost(item, host));
|
const tenant = this.findTenantForHost(tenants, host);
|
||||||
if (!tenant) {
|
if (!tenant) {
|
||||||
throw new NotFoundException('tenant not found for domain');
|
throw new NotFoundException('tenant not found for domain');
|
||||||
}
|
}
|
||||||
@@ -28,22 +28,35 @@ export class GetVersionService {
|
|||||||
return { version: tenant.appVersion || '1' };
|
return { version: tenant.appVersion || '1' };
|
||||||
}
|
}
|
||||||
|
|
||||||
private matchesHost(
|
/** همراستا با GetUserService: اول Tenant.domain، بعد aliases */
|
||||||
tenant: {
|
private findTenantForHost<
|
||||||
|
T extends {
|
||||||
domain: string;
|
domain: string;
|
||||||
domains: unknown;
|
domains: unknown;
|
||||||
},
|
},
|
||||||
host: string,
|
>(tenants: T[], host: string): T | undefined {
|
||||||
) {
|
const normalizedHost = this.normalizeHost(host);
|
||||||
const candidates = new Set<string>();
|
const hostNoWww = normalizedHost.replace(/^www\./, '');
|
||||||
for (const value of [tenant.domain, ...this.readDomains(tenant.domains)]) {
|
|
||||||
|
const primary = tenants.find((item) => {
|
||||||
|
const d = this.normalizeHost(item.domain);
|
||||||
|
return d === normalizedHost || d.replace(/^www\./, '') === hostNoWww;
|
||||||
|
});
|
||||||
|
if (primary) return primary;
|
||||||
|
|
||||||
|
return tenants.find((item) => {
|
||||||
|
for (const value of this.readDomains(item.domains)) {
|
||||||
const normalized = this.normalizeHost(value);
|
const normalized = this.normalizeHost(value);
|
||||||
if (!normalized) continue;
|
if (!normalized) continue;
|
||||||
candidates.add(normalized);
|
if (
|
||||||
candidates.add(normalized.replace(/^www\./, ''));
|
normalized === normalizedHost ||
|
||||||
candidates.add(`www.${normalized.replace(/^www\./, '')}`);
|
normalized.replace(/^www\./, '') === hostNoWww
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return candidates.has(host) || candidates.has(host.replace(/^www\./, ''));
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private readDomains(raw: unknown): string[] {
|
private readDomains(raw: unknown): string[] {
|
||||||
|
|||||||
Reference in New Issue
Block a user