mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 06:10:31 +00:00
feat: remove path alias.
feat: remove Webpack and depend on nodemon. feat: refactoring expenses. feat: optimize system users with caching. feat: architecture tenant optimize.
This commit is contained in:
@@ -1,54 +1,94 @@
|
||||
import { Service, Inject, Container } from 'typedi';
|
||||
import { Tenant, SystemUser } from '@/system/models';
|
||||
import TenantsManager from '@/system/TenantsManager';
|
||||
import { ServiceError } from '@/exceptions';
|
||||
import { ITenant } from '@/interfaces';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { ServiceError } from 'exceptions';
|
||||
import { ITenant } from 'interfaces';
|
||||
import {
|
||||
EventDispatcher,
|
||||
EventDispatcherInterface,
|
||||
} from '@/decorators/eventDispatcher';
|
||||
import events from '@/subscribers/events';
|
||||
} from 'decorators/eventDispatcher';
|
||||
import events from 'subscribers/events';
|
||||
import {
|
||||
TenantAlreadyInitialized,
|
||||
TenantAlreadySeeded,
|
||||
TenantDatabaseNotBuilt
|
||||
} from 'exceptions';
|
||||
import TenantsManager from 'services/Tenancy/TenantsManager';
|
||||
|
||||
const ERRORS = {
|
||||
TENANT_NOT_FOUND: 'tenant_not_found',
|
||||
TENANT_ALREADY_INITIALIZED: 'tenant_already_initialized',
|
||||
TENANT_ALREADY_SEEDED: 'tenant_already_seeded',
|
||||
TENANT_DB_NOT_BUILT: 'tenant_db_not_built',
|
||||
};
|
||||
@Service()
|
||||
export default class OrganizationService {
|
||||
@EventDispatcher()
|
||||
eventDispatcher: EventDispatcherInterface;
|
||||
|
||||
@Inject()
|
||||
tenantsManager: TenantsManager;
|
||||
|
||||
@Inject('dbManager')
|
||||
dbManager: any;
|
||||
|
||||
@Inject('logger')
|
||||
logger: any;
|
||||
|
||||
@Inject('repositories')
|
||||
sysRepositories: any;
|
||||
|
||||
@Inject()
|
||||
tenantsManager: TenantsManager;
|
||||
|
||||
/**
|
||||
* Builds the database schema and seed data of the given organization id.
|
||||
* @param {srting} organizationId
|
||||
* @param {srting} organizationId
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async build(organizationId: string): Promise<void> {
|
||||
const tenant = await Tenant.query().findOne('organization_id', organizationId);
|
||||
this.throwIfTenantNotExists(tenant);
|
||||
const tenant = await this.getTenantByOrgIdOrThrowError(organizationId);
|
||||
this.throwIfTenantInitizalized(tenant);
|
||||
|
||||
this.logger.info('[tenant_db_build] tenant DB creating.', { tenant });
|
||||
await this.dbManager.createDb(`bigcapital_tenant_${tenant.organizationId}`);
|
||||
|
||||
const tenantDb = this.tenantsManager.knexInstance(tenant.organizationId);
|
||||
const tenantHasDB = await this.tenantsManager.hasDatabase(tenant);
|
||||
|
||||
this.logger.info('[tenant_db_build] tenant DB migrating to latest version.', { tenant });
|
||||
await tenantDb.migrate.latest();
|
||||
try {
|
||||
if (!tenantHasDB) {
|
||||
this.logger.info('[organization] trying to create tenant database.', { organizationId });
|
||||
await this.tenantsManager.createDatabase(tenant);
|
||||
}
|
||||
this.logger.info('[organization] trying to migrate tenant database.', { organizationId });
|
||||
await this.tenantsManager.migrateTenant(tenant);
|
||||
|
||||
this.logger.info('[tenant_db_build] mark tenant as initialized.', { tenant });
|
||||
await tenant.$query().update({ initialized: true });
|
||||
// Throws `onOrganizationBuild` event.
|
||||
this.eventDispatcher.dispatch(events.organization.build, { tenant });
|
||||
|
||||
// Retrieve the tenant system user.
|
||||
const user = await SystemUser.query().findOne('tenant_id', tenant.id);
|
||||
} catch (error) {
|
||||
if (error instanceof TenantAlreadyInitialized) {
|
||||
throw new ServiceError(ERRORS.TENANT_ALREADY_INITIALIZED);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Throws `onOrganizationBuild` event.
|
||||
this.eventDispatcher.dispatch(events.organization.build, { tenant, user });
|
||||
/**
|
||||
* Seeds initial core data to the given organization tenant.
|
||||
* @param {number} organizationId
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async seed(organizationId: string): Promise<void> {
|
||||
const tenant = await this.getTenantByOrgIdOrThrowError(organizationId);
|
||||
this.throwIfTenantSeeded(tenant);
|
||||
|
||||
try {
|
||||
this.logger.info('[organization] trying to seed tenant database.', { organizationId });
|
||||
await this.tenantsManager.seedTenant(tenant);
|
||||
|
||||
// Throws `onOrganizationBuild` event.
|
||||
this.eventDispatcher.dispatch(events.organization.seeded, { tenant });
|
||||
|
||||
} catch (error) {
|
||||
if (error instanceof TenantAlreadySeeded) {
|
||||
throw new ServiceError(ERRORS.TENANT_ALREADY_SEEDED);
|
||||
} else if (error instanceof TenantDatabaseNotBuilt) {
|
||||
throw new ServiceError(ERRORS.TENANT_DB_NOT_BUILT);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,7 +98,7 @@ export default class OrganizationService {
|
||||
private throwIfTenantNotExists(tenant: ITenant) {
|
||||
if (!tenant) {
|
||||
this.logger.info('[tenant_db_build] organization id not found.');
|
||||
throw new ServiceError('tenant_not_found');
|
||||
throw new ServiceError(ERRORS.TENANT_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +107,32 @@ export default class OrganizationService {
|
||||
* @param {ITenant} tenant
|
||||
*/
|
||||
private throwIfTenantInitizalized(tenant: ITenant) {
|
||||
if (tenant.initialized) {
|
||||
throw new ServiceError('tenant_initialized');
|
||||
if (tenant.initializedAt) {
|
||||
throw new ServiceError(ERRORS.TENANT_ALREADY_INITIALIZED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws service if the tenant already seeded.
|
||||
* @param {ITenant} tenant
|
||||
*/
|
||||
private throwIfTenantSeeded(tenant: ITenant) {
|
||||
if (tenant.seededAt) {
|
||||
throw new ServiceError(ERRORS.TENANT_ALREADY_SEEDED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve tenant model by the given organization id or throw not found
|
||||
* error if the tenant not exists on the storage.
|
||||
* @param {string} organizationId
|
||||
* @return {ITenant}
|
||||
*/
|
||||
private async getTenantByOrgIdOrThrowError(organizationId: string) {
|
||||
const { tenantRepository } = this.sysRepositories;
|
||||
const tenant = await tenantRepository.getByOrgId(organizationId);
|
||||
this.throwIfTenantNotExists(tenant);
|
||||
|
||||
return tenant;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user