feat: organization setup form validation.

This commit is contained in:
a.bouhuolia
2021-09-04 13:32:14 +02:00
parent 8141674da8
commit d6d6fefd1f
14 changed files with 172 additions and 120 deletions

View File

@@ -1,4 +1,5 @@
import { Inject, Service } from 'typedi';
import moment from 'moment-timezone';
import { Router, Request, Response, NextFunction } from 'express';
import { check, ValidationChain } from 'express-validator';
@@ -8,11 +9,16 @@ import TenancyMiddleware from 'api/middleware/TenancyMiddleware';
import SubscriptionMiddleware from 'api/middleware/SubscriptionMiddleware';
import AttachCurrentTenantUser from 'api/middleware/AttachCurrentTenantUser';
import OrganizationService from 'services/Organization';
import {
ACCEPTED_CURRENCIES,
MONTHS,
ACCEPTED_LOCALES,
DATE_FORMATS,
} from 'services/Organization/constants';
import { ServiceError } from 'exceptions';
import BaseController from 'api/controllers/BaseController';
const DATE_FORMATS = ['MM/DD/YYYY', 'M/D/YYYY'];
const BASE_CURRENCY = ['USD', 'LYD'];
@Service()
export default class OrganizationController extends BaseController {
@Inject()
@@ -40,6 +46,8 @@ export default class OrganizationController extends BaseController {
);
router.put(
'/',
this.buildValidationSchema,
this.validationResult,
this.asyncMiddleware(this.updateOrganization.bind(this)),
this.handleServiceErrors.bind(this)
);
@@ -57,10 +65,11 @@ export default class OrganizationController extends BaseController {
private get buildValidationSchema(): ValidationChain[] {
return [
check('organization_name').exists().trim(),
check('base_currency').exists().isIn(BASE_CURRENCY),
check('timezone').exists(),
check('fiscal_year').exists(),
check('base_currency').exists().isIn(ACCEPTED_CURRENCIES),
check('timezone').exists().isIn(moment.tz.names()),
check('fiscal_year').exists().isIn(MONTHS),
check('industry').optional().isString(),
check('language').optional().isString().isIn(ACCEPTED_LOCALES),
check('date_format').optional().isIn(DATE_FORMATS),
];
}
@@ -80,7 +89,6 @@ export default class OrganizationController extends BaseController {
tenantId,
buildDTO
);
return res.status(200).send({
type: 'success',
code: 'ORGANIZATION.DATABASE.INITIALIZED',
@@ -117,10 +125,10 @@ export default class OrganizationController extends BaseController {
/**
* Update the organization information.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
* @returns
*/
private async updateOrganization(
req: Request,

View File

@@ -0,0 +1,34 @@
import currencies from 'js-money/lib/currency';
export const DATE_FORMATS = [
'MM.dd.yy',
'dd.MM.yy',
'yy.MM.dd',
'MM.dd.yyyy',
'dd.MM.yyyy',
'yyyy.MM.dd',
'MM/DD/YYYY',
'M/D/YYYY',
'dd MMM YYYY',
'dd MMMM YYYY',
'MMMM dd, YYYY',
'EEE, MMMM dd, YYYY',
];
export const ACCEPTED_CURRENCIES = Object.keys(currencies);
export const MONTHS = [
'january',
'february',
'march',
'april',
'may',
'june',
'july',
'august',
'september',
'october',
'november',
'december',
];
export const ACCEPTED_LOCALES = ['en', 'ar'];

View File

@@ -1,20 +1,17 @@
import { Service, Inject } from 'typedi';
import { Container } from 'typedi';
// import { ObjectId } from 'mongoose';
import { ServiceError } from 'exceptions';
import { IOrganizationBuildDTO, ISystemUser, ITenant } from 'interfaces';
import {
IOrganizationBuildDTO,
IOrganizationUpdateDTO,
ITenant,
} from 'interfaces';
import {
EventDispatcher,
EventDispatcherInterface,
} from 'decorators/eventDispatcher';
import events from 'subscribers/events';
import {
TenantAlreadyInitialized,
TenantAlreadySeeded,
TenantDatabaseNotBuilt,
} from 'exceptions';
import TenantsManager from 'services/Tenancy/TenantsManager';
import { Tenant, TenantMetadata } from 'system/models';
import { Tenant } from 'system/models';
import { ObjectId } from 'mongodb';
const ERRORS = {
@@ -60,10 +57,13 @@ export default class OrganizationService {
await this.tenantsManager.createDatabase(tenant);
// Migrate the tenant.
const migratedTenant = await this.tenantsManager.migrateTenant(tenant);
await this.tenantsManager.migrateTenant(tenant);
// Migrated tenant.
const migratedTenant = await tenant.$query();
// Seed tenant.
const seededTenant = await this.tenantsManager.seedTenant(migratedTenant);
await this.tenantsManager.seedTenant(migratedTenant);
// Markes the tenant as completed builing.
await Tenant.markAsBuilt(tenantId);
@@ -71,7 +71,7 @@ export default class OrganizationService {
// Throws `onOrganizationBuild` event.
this.eventDispatcher.dispatch(events.organization.build, {
tenant: seededTenant,
tenantId: tenant.id,
});
}
@@ -91,13 +91,14 @@ export default class OrganizationService {
this.throwIfTenantIsBuilding(tenant);
// Saves the tenant metadata.
await this.saveTenantMetadata(tenant, buildDTO);
await tenant.saveMetadata(buildDTO);
// Send welcome mail to the user.
const jobMeta = await this.agenda.now('organization-setup', {
tenantId,
buildDTO,
});
// Transformes the mangodb id to string.
const jobId = new ObjectId(jobMeta.attrs._id).toString();
// Markes the tenant as currently building.
@@ -109,12 +110,11 @@ export default class OrganizationService {
};
}
throwIfTenantIsBuilding(tenant) {
if (tenant.buildJobId) {
throw new ServiceError(ERRORS.TENANT_IS_BUILDING);
}
}
/**
* Unlocks tenant build run job.
* @param {number} tenantId
* @param {number} jobId
*/
public async revertBuildRunJob(tenantId: number, jobId: string) {
await Tenant.markAsBuildCompleted(tenantId, jobId);
}
@@ -135,6 +135,23 @@ export default class OrganizationService {
return tenant;
}
/**
* Updates organization information.
* @param {ITenant} tenantId
* @param {IOrganizationUpdateDTO} organizationDTO
*/
public async updateOrganization(
tenantId: number,
organizationDTO: IOrganizationUpdateDTO
): Promise<void> {
const tenant = await Tenant.query().findById(tenantId);
// Throw error if the tenant not exists.
this.throwIfTenantNotExists(tenant);
await tenant.saveMetadata(organizationDTO);
}
/**
* Throws error in case the given tenant is undefined.
* @param {ITenant} tenant
@@ -156,16 +173,13 @@ export default class OrganizationService {
}
/**
* Saves the organization metadata.
* @param tenant
* @param buildDTO
* @returns
* Throw error if the tenant is building.
* @param {ITenant} tenant
*/
private saveTenantMetadata(tenant: ITenant, buildDTO) {
return TenantMetadata.query().insert({
tenantId: tenant.id,
...buildDTO,
});
private throwIfTenantIsBuilding(tenant) {
if (tenant.buildJobId) {
throw new ServiceError(ERRORS.TENANT_IS_BUILDING);
}
}
/**

View File

@@ -7,6 +7,7 @@ exports.up = function (knex) {
table.string('industry');
table.string('base_currency');
table.string('language');
table.string('timezone');
table.string('date_format');