import { Inject, Service } from 'typedi'; import { ObjectId } from 'mongodb'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import { SeedMigration } from '@/lib/Seeder/SeedMigration'; import { Tenant } from '@/system/models'; import { ServiceError } from '@/exceptions'; import TenantDBManager from '@/services/Tenancy/TenantDBManager'; import config from '../../config'; import { ERRORS } from './constants'; import OrganizationService from './OrganizationService'; import TenantsManagerService from '@/services/Tenancy/TenantsManager'; @Service() export default class OrganizationUpgrade { @Inject() private organizationService: OrganizationService; @Inject() private tenantsManager: TenantsManagerService; @Inject('agenda') private agenda: any; /** * Upgrades the given organization database. * @param {number} tenantId - Tenant id. * @returns {Promise} */ public upgradeJob = async (tenantId: number): Promise => { const tenant = await Tenant.query() .findById(tenantId) .withGraphFetched('metadata'); // Validate tenant version. this.validateTenantVersion(tenant); // Initialize the tenant. const seedContext = this.tenantsManager.getSeedMigrationContext(tenant); // Database manager. const dbManager = new TenantDBManager(); // Migrate the organization database schema. await dbManager.migrate(tenant); // Seeds the organization database data. await new SeedMigration(seedContext.knex, seedContext).latest(); // Update the organization database version. await this.organizationService.flagTenantDBBatch(tenantId); // Remove the tenant job id. await Tenant.markAsUpgraded(tenantId); }; /** * Running organization upgrade job. * @param {number} tenantId - Tenant id. * @return {Promise} */ public upgrade = async (tenantId: number): Promise<{ jobId: string }> => { const tenant = await Tenant.query().findById(tenantId); // Validate tenant version. this.validateTenantVersion(tenant); // Validate tenant upgrade is not running. this.validateTenantUpgradeNotRunning(tenant); // Send welcome mail to the user. const jobMeta = await this.agenda.now('organization-upgrade', { tenantId, }); // Transformes the mangodb id to string. const jobId = new ObjectId(jobMeta.attrs._id).toString(); // Markes the tenant as currently building. await Tenant.markAsUpgrading(tenantId, jobId); return { jobId }; }; /** * Validates the given tenant version. * @param {ITenant} tenant */ private validateTenantVersion(tenant) { if (tenant.databaseBatch >= config.databaseBatch) { throw new ServiceError(ERRORS.TENANT_DATABASE_UPGRADED); } } /** * Validates the given tenant upgrade is not running. * @param tenant */ private validateTenantUpgradeNotRunning(tenant) { if (tenant.isUpgradeRunning) { throw new ServiceError(ERRORS.TENANT_UPGRADE_IS_RUNNING); } } }