forked from wangziqi/gongxue-base
117 lines
4.3 KiB
TypeScript
117 lines
4.3 KiB
TypeScript
import { config } from '../../core/config.js';
|
|
import { queryOne } from '../../core/db.js';
|
|
import { getHeader, type RequestContext } from '../../core/http.js';
|
|
|
|
interface TenantResolveRow {
|
|
id: string;
|
|
slug: string;
|
|
name: string;
|
|
status: string;
|
|
mode: string;
|
|
host: string | null;
|
|
brand_name: string | null;
|
|
short_name: string | null;
|
|
slogan: string | null;
|
|
logo_url: string | null;
|
|
favicon_url: string | null;
|
|
service_wechat: string | null;
|
|
service_account_name: string | null;
|
|
theme: Record<string, unknown>;
|
|
public_assets: Record<string, unknown>;
|
|
feature_flags: Record<string, unknown>;
|
|
admin_feature_flags: Record<string, unknown>;
|
|
public_config: Record<string, unknown>;
|
|
}
|
|
|
|
function normalizeHost(host: string) {
|
|
return host.split(':')[0]?.trim().toLowerCase() || '';
|
|
}
|
|
|
|
export async function resolveTenantRoute(ctx: RequestContext) {
|
|
const hostParam = ctx.url.searchParams.get('host') || '';
|
|
const tenantCode = ctx.url.searchParams.get('tenantCode') || getHeader(ctx.req, 'x-tenant-code');
|
|
const requestHost = normalizeHost(hostParam || getHeader(ctx.req, 'x-forwarded-host') || getHeader(ctx.req, 'host'));
|
|
|
|
const row = tenantCode
|
|
? await queryOne<TenantResolveRow>(
|
|
`
|
|
select t.id, t.slug, t.name, t.status, t.mode,
|
|
null::text as host,
|
|
b.brand_name, b.short_name, b.slogan, b.logo_url, b.favicon_url,
|
|
b.service_wechat, b.service_account_name,
|
|
coalesce(tc.active_theme, b.theme, '{}'::jsonb) as theme,
|
|
coalesce(b.public_assets, tc.active_public_assets, '{}'::jsonb) as public_assets,
|
|
coalesce(s.feature_flags, '{}'::jsonb) as feature_flags,
|
|
coalesce(s.admin_feature_flags, '{}'::jsonb) as admin_feature_flags,
|
|
coalesce(s.public_config, '{}'::jsonb) as public_config
|
|
from public.tenants t
|
|
left join public.tenant_branding b on b.tenant_id = t.id
|
|
left join public.tenant_settings s on s.tenant_id = t.id
|
|
left join public.tenant_theme_configs tc on tc.tenant_id = t.id and tc.status = 'published'
|
|
where t.slug = $1 and t.status = 'active'
|
|
limit 1
|
|
`,
|
|
[tenantCode],
|
|
)
|
|
: await queryOne<TenantResolveRow>(
|
|
`
|
|
select t.id, t.slug, t.name, t.status, t.mode,
|
|
d.host::text,
|
|
b.brand_name, b.short_name, b.slogan, b.logo_url, b.favicon_url,
|
|
b.service_wechat, b.service_account_name,
|
|
coalesce(tc.active_theme, b.theme, '{}'::jsonb) as theme,
|
|
coalesce(b.public_assets, tc.active_public_assets, '{}'::jsonb) as public_assets,
|
|
coalesce(s.feature_flags, '{}'::jsonb) as feature_flags,
|
|
coalesce(s.admin_feature_flags, '{}'::jsonb) as admin_feature_flags,
|
|
coalesce(s.public_config, '{}'::jsonb) as public_config
|
|
from public.tenant_domains d
|
|
join public.tenants t on t.id = d.tenant_id
|
|
left join public.tenant_branding b on b.tenant_id = t.id
|
|
left join public.tenant_settings s on s.tenant_id = t.id
|
|
left join public.tenant_theme_configs tc on tc.tenant_id = t.id and tc.status = 'published'
|
|
where d.host = $1 and d.status = 'active' and t.status = 'active'
|
|
limit 1
|
|
`,
|
|
[requestHost || 'localhost'],
|
|
);
|
|
|
|
if (!row && requestHost !== 'localhost') {
|
|
ctx.url.searchParams.set('tenantCode', config.defaultTenantSlug);
|
|
return resolveTenantRoute(ctx);
|
|
}
|
|
|
|
if (!row) {
|
|
return {
|
|
found: false,
|
|
message: 'Tenant not found',
|
|
lookup: { host: requestHost, tenantCode: tenantCode || null },
|
|
};
|
|
}
|
|
|
|
return {
|
|
found: true,
|
|
tenant: {
|
|
id: row.id,
|
|
slug: row.slug,
|
|
name: row.name,
|
|
status: row.status,
|
|
mode: row.mode,
|
|
host: row.host,
|
|
},
|
|
branding: {
|
|
brandName: row.brand_name || row.name,
|
|
shortName: row.short_name || row.name,
|
|
slogan: row.slogan || '',
|
|
logoUrl: row.logo_url || '',
|
|
faviconUrl: row.favicon_url || '',
|
|
serviceWechat: row.service_wechat || '',
|
|
serviceAccountName: row.service_account_name || '',
|
|
theme: row.theme || {},
|
|
publicAssets: row.public_assets || {},
|
|
},
|
|
features: row.feature_flags || {},
|
|
adminFeatures: row.admin_feature_flags || {},
|
|
publicConfig: row.public_config || {},
|
|
};
|
|
}
|