mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
fix: hotbugs in multi-tenant arch.
This commit is contained in:
13
server/cli/tenants.js
Normal file
13
server/cli/tenants.js
Normal file
@@ -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);
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import TenantsManager from '@/system/TenantsManager';
|
import TenantsManager from '@/system/TenantsManager';
|
||||||
import Model from '@/models/Model';
|
import TenantModel from '@/models/TenantModel';
|
||||||
|
|
||||||
function loadModelsFromDirectory() {
|
function loadModelsFromDirectory() {
|
||||||
const models = {};
|
const models = {};
|
||||||
@@ -18,23 +18,29 @@ function loadModelsFromDirectory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async (req, res, next) => {
|
export default async (req, res, next) => {
|
||||||
const { organization: organizationId } = req.query;
|
const organizationId = req.headers['organization-id'] || req.query.organization;
|
||||||
const notFoundOrganization = () => res.status(400).send({
|
const notFoundOrganization = () => res.boom.unauthorized(
|
||||||
errors: [{ type: 'ORGANIZATION.ID.NOT.FOUND' }],
|
'Organization identication not found.',
|
||||||
});
|
{ errors: [{ type: 'ORGANIZATION.ID.NOT.FOUND', code: 100 }] },
|
||||||
|
);
|
||||||
|
|
||||||
if (!organizationId) {
|
if (!organizationId) {
|
||||||
return notFoundOrganization();
|
return notFoundOrganization();
|
||||||
}
|
}
|
||||||
const tenant = await TenantsManager.getTenant(organizationId);
|
const tenant = await TenantsManager.getTenant(organizationId);
|
||||||
|
|
||||||
|
// When the given organization id not found on the system storage.
|
||||||
if (!tenant) {
|
if (!tenant) {
|
||||||
return notFoundOrganization();
|
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 knex = TenantsManager.knexInstance(organizationId);
|
||||||
const models = loadModelsFromDirectory();
|
const models = loadModelsFromDirectory();
|
||||||
|
|
||||||
Model.knexBinded = knex;
|
TenantModel.knexBinded = knex;
|
||||||
|
|
||||||
req.knex = knex;
|
req.knex = knex;
|
||||||
req.organizationId = organizationId;
|
req.organizationId = organizationId;
|
||||||
@@ -42,7 +48,7 @@ export default async (req, res, next) => {
|
|||||||
...Object.values(models).reduce((acc, model) => {
|
...Object.values(models).reduce((acc, model) => {
|
||||||
if (model.resource
|
if (model.resource
|
||||||
&& model.resource.default
|
&& model.resource.default
|
||||||
&& Object.getPrototypeOf(model.resource.default) === Model) {
|
&& Object.getPrototypeOf(model.resource.default) === TenantModel) {
|
||||||
acc[model.name] = model.resource.default.bindKnex(knex);
|
acc[model.name] = model.resource.default.bindKnex(knex);
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
|
|||||||
@@ -1,23 +1,14 @@
|
|||||||
/* eslint-disable consistent-return */
|
/* eslint-disable consistent-return */
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import SystemUser from '@/system/models/SystemUser';
|
import SystemUser from '@/system/models/SystemUser';
|
||||||
// import Auth from '@/models/Auth';
|
|
||||||
|
|
||||||
const authMiddleware = (req, res, next) => {
|
const authMiddleware = (req, res, next) => {
|
||||||
const { JWT_SECRET_KEY } = process.env;
|
const { JWT_SECRET_KEY } = process.env;
|
||||||
const token = req.headers['x-access-token'] || req.query.token;
|
const token = req.headers['x-access-token'] || req.query.token;
|
||||||
|
|
||||||
const onError = () => {
|
const onError = () => { res.boom.unauthorized(); };
|
||||||
// Auth.loggedOut();
|
|
||||||
res.status(401).send({
|
|
||||||
success: false,
|
|
||||||
message: 'unauthorized',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!token) {
|
if (!token) { return onError(); }
|
||||||
return onError();
|
|
||||||
}
|
|
||||||
|
|
||||||
const verify = new Promise((resolve, reject) => {
|
const verify = new Promise((resolve, reject) => {
|
||||||
jwt.verify(token, JWT_SECRET_KEY, async (error, decoded) => {
|
jwt.verify(token, JWT_SECRET_KEY, async (error, decoded) => {
|
||||||
@@ -26,7 +17,6 @@ const authMiddleware = (req, res, next) => {
|
|||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
req.user = await SystemUser.query().findById(decoded._id);
|
req.user = await SystemUser.query().findById(decoded._id);
|
||||||
// Auth.setAuthenticatedUser(req.user);
|
|
||||||
|
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
return onError();
|
return onError();
|
||||||
|
|||||||
@@ -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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
import { Model } from 'objection';
|
|
||||||
import path from 'path';
|
|
||||||
import TenantModel from '@/models/TenantModel';
|
import TenantModel from '@/models/TenantModel';
|
||||||
import ResourceFieldMetadataCollection from '@/collection/ResourceFieldMetadataCollection';
|
import ResourceFieldMetadataCollection from '@/collection/ResourceFieldMetadataCollection';
|
||||||
|
|
||||||
@@ -17,23 +15,4 @@ export default class ResourceFieldMetadata extends TenantModel {
|
|||||||
static get collection() {
|
static get collection() {
|
||||||
return ResourceFieldMetadataCollection;
|
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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Knex from 'knex';
|
import Knex from 'knex';
|
||||||
|
import { knexSnakeCaseMappers } from 'objection';
|
||||||
import Tenant from '@/system/models/Tenant';
|
import Tenant from '@/system/models/Tenant';
|
||||||
import config from '@/../config/config';
|
import config from '@/../config/config';
|
||||||
|
|
||||||
@@ -50,7 +51,10 @@ export default class TenantsManager {
|
|||||||
let knex = knexCache.get(organizationId);
|
let knex = knexCache.get(organizationId);
|
||||||
|
|
||||||
if (!knex) {
|
if (!knex) {
|
||||||
knex = Knex(this.getTenantKnexConfig(organizationId));
|
knex = Knex({
|
||||||
|
...this.getTenantKnexConfig(organizationId),
|
||||||
|
...knexSnakeCaseMappers({ upperCase: true }),
|
||||||
|
});
|
||||||
knexCache.set(organizationId, knex);
|
knexCache.set(organizationId, knex);
|
||||||
}
|
}
|
||||||
return knex;
|
return knex;
|
||||||
|
|||||||
Reference in New Issue
Block a user