From 1e13aa16acac972f65bf86b0bc6da72339dad1b1 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 22 Apr 2020 01:12:24 +0200 Subject: [PATCH] fix: hotbugs in multi-tenant arch. --- server/cli/tenants.js | 13 +++++++ .../src/http/middleware/TenancyMiddleware.js | 20 ++++++---- server/src/http/middleware/jwtAuth.js | 14 +------ server/src/models/ItemMetadata.js | 39 ------------------- server/src/models/ResourceFieldMetadata.js | 21 ---------- server/src/system/TenantsManager.js | 6 ++- 6 files changed, 33 insertions(+), 80 deletions(-) create mode 100644 server/cli/tenants.js delete mode 100644 server/src/models/ItemMetadata.js diff --git a/server/cli/tenants.js b/server/cli/tenants.js new file mode 100644 index 000000000..b601e432d --- /dev/null +++ b/server/cli/tenants.js @@ -0,0 +1,13 @@ +import { program } from 'commander'; + +program + .version('0.0.1') + .description('An application for pizzas ordering') + .command('tenants:migrate') + .description('Migrate all tenants or the given tenant id.') + .option('-t, --tenant_id [tenant_id]', 'Which tenant id do you migrate.') + .action(async () => { + + }); + +program.parse(process.argv); \ No newline at end of file diff --git a/server/src/http/middleware/TenancyMiddleware.js b/server/src/http/middleware/TenancyMiddleware.js index fef5fc49e..cc5602be6 100644 --- a/server/src/http/middleware/TenancyMiddleware.js +++ b/server/src/http/middleware/TenancyMiddleware.js @@ -1,7 +1,7 @@ import fs from 'fs'; import path from 'path'; import TenantsManager from '@/system/TenantsManager'; -import Model from '@/models/Model'; +import TenantModel from '@/models/TenantModel'; function loadModelsFromDirectory() { const models = {}; @@ -18,23 +18,29 @@ function loadModelsFromDirectory() { } export default async (req, res, next) => { - const { organization: organizationId } = req.query; - const notFoundOrganization = () => res.status(400).send({ - errors: [{ type: 'ORGANIZATION.ID.NOT.FOUND' }], - }); + const organizationId = req.headers['organization-id'] || req.query.organization; + const notFoundOrganization = () => res.boom.unauthorized( + 'Organization identication not found.', + { errors: [{ type: 'ORGANIZATION.ID.NOT.FOUND', code: 100 }] }, + ); if (!organizationId) { return notFoundOrganization(); } const tenant = await TenantsManager.getTenant(organizationId); + // When the given organization id not found on the system storage. if (!tenant) { return notFoundOrganization(); } + // When user tenant not match the given organization id. + if (tenant.id !== req.user.tenantId) { + return res.boom.unauthorized(); + } const knex = TenantsManager.knexInstance(organizationId); const models = loadModelsFromDirectory(); - Model.knexBinded = knex; + TenantModel.knexBinded = knex; req.knex = knex; req.organizationId = organizationId; @@ -42,7 +48,7 @@ export default async (req, res, next) => { ...Object.values(models).reduce((acc, model) => { if (model.resource && model.resource.default - && Object.getPrototypeOf(model.resource.default) === Model) { + && Object.getPrototypeOf(model.resource.default) === TenantModel) { acc[model.name] = model.resource.default.bindKnex(knex); } return acc; diff --git a/server/src/http/middleware/jwtAuth.js b/server/src/http/middleware/jwtAuth.js index 4ab780419..eb879bcb8 100644 --- a/server/src/http/middleware/jwtAuth.js +++ b/server/src/http/middleware/jwtAuth.js @@ -1,23 +1,14 @@ /* eslint-disable consistent-return */ import jwt from 'jsonwebtoken'; import SystemUser from '@/system/models/SystemUser'; -// import Auth from '@/models/Auth'; const authMiddleware = (req, res, next) => { const { JWT_SECRET_KEY } = process.env; const token = req.headers['x-access-token'] || req.query.token; - const onError = () => { - // Auth.loggedOut(); - res.status(401).send({ - success: false, - message: 'unauthorized', - }); - }; + const onError = () => { res.boom.unauthorized(); }; - if (!token) { - return onError(); - } + if (!token) { return onError(); } const verify = new Promise((resolve, reject) => { jwt.verify(token, JWT_SECRET_KEY, async (error, decoded) => { @@ -26,7 +17,6 @@ const authMiddleware = (req, res, next) => { } else { // eslint-disable-next-line no-underscore-dangle req.user = await SystemUser.query().findById(decoded._id); - // Auth.setAuthenticatedUser(req.user); if (!req.user) { return onError(); diff --git a/server/src/models/ItemMetadata.js b/server/src/models/ItemMetadata.js deleted file mode 100644 index 7b5e5cc72..000000000 --- a/server/src/models/ItemMetadata.js +++ /dev/null @@ -1,39 +0,0 @@ -import { Model } from 'objection'; -import TenantModel from '@/models/TenantModel'; - -export default class ItemMetadata extends TenantModel { - /** - * Table name - */ - static get tableName() { - return 'items_metadata'; - } - - /** - * Timestamp columns. - */ - static get hasTimestamps() { - return ['created_at', 'updated_at']; - } - - /** - * Relationship mapping. - */ - static get relationMappings() { - const Item = require('@/models/Item'); - - return { - /** - * Item category may has many items. - */ - items: { - relation: Model.BelongsToOneRelation, - modelBase: this.relationBindKnex(Item.default), - join: { - from: 'items_metadata.item_id', - to: 'items.id', - }, - }, - }; - } -} diff --git a/server/src/models/ResourceFieldMetadata.js b/server/src/models/ResourceFieldMetadata.js index 7957417d0..89ceebcff 100644 --- a/server/src/models/ResourceFieldMetadata.js +++ b/server/src/models/ResourceFieldMetadata.js @@ -1,5 +1,3 @@ -import { Model } from 'objection'; -import path from 'path'; import TenantModel from '@/models/TenantModel'; import ResourceFieldMetadataCollection from '@/collection/ResourceFieldMetadataCollection'; @@ -17,23 +15,4 @@ export default class ResourceFieldMetadata extends TenantModel { static get collection() { return ResourceFieldMetadataCollection; } - - /** - * Relationship mapping. - */ - static get relationMappings() { - return { - /** - * Resource field may belongs to resource model. - */ - resource: { - relation: Model.BelongsToOneRelation, - modelBase: path.join(__dirname, 'Resource'), - join: { - from: 'resource_fields.resource_id', - to: 'resources.id', - }, - }, - }; - } } diff --git a/server/src/system/TenantsManager.js b/server/src/system/TenantsManager.js index dd16f81dc..4f843228b 100644 --- a/server/src/system/TenantsManager.js +++ b/server/src/system/TenantsManager.js @@ -1,4 +1,5 @@ import Knex from 'knex'; +import { knexSnakeCaseMappers } from 'objection'; import Tenant from '@/system/models/Tenant'; import config from '@/../config/config'; @@ -50,7 +51,10 @@ export default class TenantsManager { let knex = knexCache.get(organizationId); if (!knex) { - knex = Knex(this.getTenantKnexConfig(organizationId)); + knex = Knex({ + ...this.getTenantKnexConfig(organizationId), + ...knexSnakeCaseMappers({ upperCase: true }), + }); knexCache.set(organizationId, knex); } return knex;