Files
bigcapital/packages/server/src/modules/Tenancy/EnsureTenantIsSeeded.guards.ts
2026-02-23 00:37:56 +02:00

65 lines
2.0 KiB
TypeScript

import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
SetMetadata,
UnauthorizedException,
} from '@nestjs/common';
import { TenancyContext } from './TenancyContext.service';
import { Reflector } from '@nestjs/core';
import { IS_PUBLIC_ROUTE } from '../Auth/Auth.constants';
import { IS_TENANT_AGNOSTIC } from './TenancyGlobal.guard';
export const IS_IGNORE_TENANT_SEEDED = 'IS_IGNORE_TENANT_SEEDED';
export const IgnoreTenantSeededRoute = () =>
SetMetadata(IS_IGNORE_TENANT_SEEDED, true);
@Injectable()
export class EnsureTenantIsSeededGuard implements CanActivate {
constructor(
private readonly tenancyContext: TenancyContext,
private reflector: Reflector,
) { }
/**
* Validate the tenant of the current request is seeded.
* @param {ExecutionContext} context
* @returns {Promise<boolean>}
*/
async canActivate(context: ExecutionContext): Promise<boolean> {
const isPublic = this.reflector.getAllAndOverride<boolean>(
IS_PUBLIC_ROUTE,
[context.getHandler(), context.getClass()],
);
const isIgnoreEnsureTenantSeeded =
this.reflector.getAllAndOverride<boolean>(IS_IGNORE_TENANT_SEEDED, [
context.getHandler(),
context.getClass(),
]);
const isTenantAgnostic = this.reflector.getAllAndOverride<boolean>(
IS_TENANT_AGNOSTIC,
[context.getHandler(), context.getClass()],
);
// Skip the guard early if the route marked as public, tenant agnostic or ignored.
if (isPublic || isIgnoreEnsureTenantSeeded || isTenantAgnostic) {
return true;
}
const tenant = await this.tenancyContext.getTenant();
if (!tenant) {
throw new UnauthorizedException({
message: 'Tenant not found.',
errors: [{ type: 'TENANT.NOT.FOUND' }],
});
}
if (!tenant.seededAt) {
throw new UnauthorizedException({
message: 'Tenant database is not seeded with initial data yet.',
errors: [{ type: 'TENANT.DATABASE.NOT.SEED' }],
});
}
return true;
}
}