mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
198 lines
5.2 KiB
TypeScript
198 lines
5.2 KiB
TypeScript
import { Container, Inject, Service } from 'typedi';
|
|
import { ITenantManager, ITenant, ITenantDBManager } from '@/interfaces';
|
|
import {
|
|
EventDispatcherInterface,
|
|
EventDispatcher,
|
|
} from 'decorators/eventDispatcher';
|
|
import {
|
|
TenantAlreadyInitialized,
|
|
TenantAlreadySeeded,
|
|
TenantDatabaseNotBuilt,
|
|
} from '@/exceptions';
|
|
import TenantDBManager from '@/services/Tenancy/TenantDBManager';
|
|
import events from '@/subscribers/events';
|
|
import { Tenant } from '@/system/models';
|
|
import { SeedMigration } from '@/lib/Seeder/SeedMigration';
|
|
import i18n from '../../loaders/i18n';
|
|
|
|
const ERRORS = {
|
|
TENANT_ALREADY_CREATED: 'TENANT_ALREADY_CREATED',
|
|
TENANT_NOT_EXISTS: 'TENANT_NOT_EXISTS',
|
|
};
|
|
|
|
// Tenants manager service.
|
|
@Service()
|
|
export default class TenantsManagerService implements ITenantManager {
|
|
static instances: { [key: number]: ITenantManager } = {};
|
|
|
|
@EventDispatcher()
|
|
private eventDispatcher: EventDispatcherInterface;
|
|
|
|
@Inject('repositories')
|
|
private sysRepositories: any;
|
|
|
|
private tenantDBManager: ITenantDBManager;
|
|
|
|
/**
|
|
* Constructor method.
|
|
*/
|
|
constructor() {
|
|
this.tenantDBManager = new TenantDBManager();
|
|
}
|
|
|
|
/**
|
|
* Creates a new teant with unique organization id.
|
|
* @param {ITenant} tenant
|
|
* @return {Promise<ITenant>}
|
|
*/
|
|
public async createTenant(): Promise<ITenant> {
|
|
const { tenantRepository } = this.sysRepositories;
|
|
const tenant = await tenantRepository.createWithUniqueOrgId();
|
|
|
|
return tenant;
|
|
}
|
|
|
|
/**
|
|
* Creates a new tenant database.
|
|
* @param {ITenant} tenant -
|
|
* @return {Promise<void>}
|
|
*/
|
|
public async createDatabase(tenant: ITenant): Promise<void> {
|
|
this.throwErrorIfTenantAlreadyInitialized(tenant);
|
|
|
|
await this.tenantDBManager.createDatabase(tenant);
|
|
|
|
this.eventDispatcher.dispatch(events.tenantManager.databaseCreated);
|
|
}
|
|
|
|
/**
|
|
* Drops the database if the given tenant.
|
|
* @param {number} tenantId
|
|
*/
|
|
async dropDatabaseIfExists(tenant: ITenant) {
|
|
// Drop the database if exists.
|
|
await this.tenantDBManager.dropDatabaseIfExists(tenant);
|
|
}
|
|
|
|
/**
|
|
* Detarmines the tenant has database.
|
|
* @param {ITenant} tenant
|
|
* @returns {Promise<boolean>}
|
|
*/
|
|
public async hasDatabase(tenant: ITenant): Promise<boolean> {
|
|
return this.tenantDBManager.databaseExists(tenant);
|
|
}
|
|
|
|
/**
|
|
* Migrates the tenant database.
|
|
* @param {ITenant} tenant
|
|
* @return {Promise<void>}
|
|
*/
|
|
public async migrateTenant(tenant: ITenant): Promise<void> {
|
|
// Throw error if the tenant already initialized.
|
|
this.throwErrorIfTenantAlreadyInitialized(tenant);
|
|
|
|
// Migrate the database tenant.
|
|
await this.tenantDBManager.migrate(tenant);
|
|
|
|
// Mark the tenant as initialized.
|
|
await Tenant.markAsInitialized(tenant.id);
|
|
|
|
// Triggers `onTenantMigrated` event.
|
|
this.eventDispatcher.dispatch(events.tenantManager.tenantMigrated, {
|
|
tenantId: tenant.id,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Seeds the tenant database.
|
|
* @param {ITenant} tenant
|
|
* @return {Promise<void>}
|
|
*/
|
|
public async seedTenant(tenant: ITenant, tenancyContext): Promise<void> {
|
|
// Throw error if the tenant is not built yet.
|
|
this.throwErrorIfTenantNotBuilt(tenant);
|
|
|
|
// Throw error if the tenant is not seeded yet.
|
|
this.throwErrorIfTenantAlreadySeeded(tenant);
|
|
|
|
// Seeds the organization database data.
|
|
await new SeedMigration(tenancyContext.knex, tenancyContext).latest();
|
|
|
|
// Mark the tenant as seeded in specific date.
|
|
await Tenant.markAsSeeded(tenant.id);
|
|
|
|
// Triggers `onTenantSeeded` event.
|
|
this.eventDispatcher.dispatch(events.tenantManager.tenantSeeded, {
|
|
tenantId: tenant.id,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize knex instance or retrieve the instance of cache map.
|
|
* @param {ITenant} tenant
|
|
* @returns {Knex}
|
|
*/
|
|
public setupKnexInstance(tenant: ITenant) {
|
|
return this.tenantDBManager.setupKnexInstance(tenant);
|
|
}
|
|
|
|
/**
|
|
* Retrieve tenant knex instance or throw error in case was not initialized.
|
|
* @param {number} tenantId
|
|
* @returns {Knex}
|
|
*/
|
|
public getKnexInstance(tenantId: number) {
|
|
return this.tenantDBManager.getKnexInstance(tenantId);
|
|
}
|
|
|
|
/**
|
|
* Throws error if the tenant already seeded.
|
|
* @throws {TenantAlreadySeeded}
|
|
*/
|
|
private throwErrorIfTenantAlreadySeeded(tenant: ITenant) {
|
|
if (tenant.seededAt) {
|
|
throw new TenantAlreadySeeded();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Throws error if the tenant database is not built yut.
|
|
* @param {ITenant} tenant
|
|
*/
|
|
private throwErrorIfTenantNotBuilt(tenant: ITenant) {
|
|
if (!tenant.initializedAt) {
|
|
throw new TenantDatabaseNotBuilt();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Throws error if the tenant already migrated.
|
|
* @throws {TenantAlreadyInitialized}
|
|
*/
|
|
private throwErrorIfTenantAlreadyInitialized(tenant: ITenant) {
|
|
if (tenant.initializedAt) {
|
|
throw new TenantAlreadyInitialized();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize seed migration contxt.
|
|
* @param {ITenant} tenant
|
|
* @returns
|
|
*/
|
|
public getSeedMigrationContext(tenant: ITenant) {
|
|
// Initialize the knex instance.
|
|
const knex = this.setupKnexInstance(tenant);
|
|
const i18nInstance = i18n();
|
|
|
|
i18nInstance.setLocale(tenant.metadata.language);
|
|
|
|
return {
|
|
knex,
|
|
i18n: i18nInstance,
|
|
tenant,
|
|
};
|
|
}
|
|
}
|