import { Inject, Service } from 'typedi'; import { Router, Request, Response, NextFunction } from 'express'; import asyncMiddleware from 'api/middleware/asyncMiddleware'; import JWTAuth from 'api/middleware/jwtAuth'; import TenancyMiddleware from 'api/middleware/TenancyMiddleware'; import SubscriptionMiddleware from 'api/middleware/SubscriptionMiddleware'; import AttachCurrentTenantUser from 'api/middleware/AttachCurrentTenantUser'; import OrganizationService from 'services/Organization'; import { ServiceError } from 'exceptions'; import BaseController from 'api/controllers/BaseController'; import EnsureConfiguredMiddleware from 'api/middleware/EnsureConfiguredMiddleware'; import SettingsMiddleware from 'api/middleware/SettingsMiddleware'; @Service() export default class OrganizationController extends BaseController { @Inject() organizationService: OrganizationService; /** * Router constructor. */ router() { const router = Router(); // Should before build tenant database the user be authorized and // most important than that, should be subscribed to any plan. router.use(JWTAuth); router.use(AttachCurrentTenantUser); router.use(TenancyMiddleware); // Should to seed organization tenant be configured. router.use('/seed', SubscriptionMiddleware('main')); router.use('/seed', SettingsMiddleware); router.use('/seed', EnsureConfiguredMiddleware); router.use('/build', SubscriptionMiddleware('main')); router.post('/build', asyncMiddleware(this.build.bind(this))); router.post('/seed', asyncMiddleware(this.seed.bind(this))); router.get('/all', asyncMiddleware(this.allOrganizations.bind(this))); router.get( '/current', asyncMiddleware(this.currentOrganization.bind(this)) ); return router; } /** * Builds tenant database and migrate database schema. * @param {Request} req - Express request. * @param {Response} res - Express response. * @param {NextFunction} next */ async build(req: Request, res: Response, next: Function) { const { organizationId } = req.tenant; const { user } = req; try { await this.organizationService.build(organizationId, user); return res.status(200).send({ type: 'success', code: 'ORGANIZATION.DATABASE.INITIALIZED', message: 'The organization database has been initialized.', }); } catch (error) { if (error instanceof ServiceError) { if (error.errorType === 'tenant_not_found') { return res.status(400).send({ // errors: [{ type: 'TENANT.NOT.FOUND', code: 100 }], }); } if (error.errorType === 'tenant_already_initialized') { return res.status(400).send({ errors: [{ type: 'TENANT.DATABASE.ALREADY.BUILT', code: 200 }], }); } } next(error); } } /** * Seeds initial data to tenant database. * @param {Request} req * @param {Response} res * @param {NextFunction} next */ async seed(req: Request, res: Response, next: Function) { const { organizationId } = req.tenant; try { await this.organizationService.seed(organizationId); return res.status(200).send({ type: 'success', code: 'ORGANIZATION.DATABASE.SEED', message: 'The organization database has been seeded.', }); } catch (error) { if (error instanceof ServiceError) { if (error.errorType === 'tenant_not_found') { return res.status(400).send({ errors: [{ type: 'TENANT.NOT.FOUND', code: 100 }], }); } if (error.errorType === 'tenant_already_seeded') { return res.status(400).send({ errors: [{ type: 'TENANT.DATABASE.ALREADY.SEEDED', code: 200 }], }); } if (error.errorType === 'tenant_db_not_built') { return res.status(400).send({ errors: [{ type: 'TENANT.DATABASE.NOT.BUILT', code: 300 }], }); } } next(error); } } /** * Listing all organizations that assocaited to the authorized user. * @param {Request} req * @param {Response} res * @param {NextFunction} next */ async allOrganizations(req: Request, res: Response, next: NextFunction) { const { user } = req; try { const organizations = await this.organizationService.listOrganizations( user ); return res.status(200).send({ organizations }); } catch (error) { next(error); } } /** * Retrieve the current organization of the associated authenticated user. * @param {Request} req * @param {Response} res * @param {NextFunction} next */ async currentOrganization(req: Request, res: Response, next: NextFunction) { const { tenantId } = req; try { const organization = await this.organizationService.currentOrganization( tenantId ); return res.status(200).send({ organization }); } catch (error) { next(error); } } }