mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
WIP Multi-tenant architecture.
This commit is contained in:
58
server/src/system/TenantsManager.js
Normal file
58
server/src/system/TenantsManager.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import Knex from 'knex';
|
||||
import Tenant from '@/system/models/Tenant';
|
||||
import config from '@/../config/config';
|
||||
|
||||
export default class TenantsManager {
|
||||
|
||||
constructor() {
|
||||
this.knexCache = new Map();
|
||||
}
|
||||
|
||||
static async getTenant(organizationId) {
|
||||
const tenant = await Tenant.query()
|
||||
.where('organization_id', organizationId).first();
|
||||
|
||||
return tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all tenants metadata from system storage.
|
||||
*/
|
||||
static getAllTenants() {
|
||||
return Tenant.query();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the given organization id knex configuration.
|
||||
* @param {String} organizationId -
|
||||
*/
|
||||
static getTenantKnexConfig(organizationId) {
|
||||
return {
|
||||
client: config.tenant.db_client,
|
||||
connection: {
|
||||
host: config.tenant.db_host,
|
||||
user: config.tenant.db_user,
|
||||
password: config.tenant.db_password,
|
||||
database: `${config.tenant.db_name_prefix}${organizationId}`,
|
||||
charset: config.tenant.charset,
|
||||
},
|
||||
migrations: {
|
||||
directory: config.tenant.migrations_dir,
|
||||
},
|
||||
seeds: {
|
||||
directory: config.tenant.seeds_dir,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static knexInstance(organizationId) {
|
||||
const knexCache = new Map();
|
||||
let knex = knexCache.get(organizationId);
|
||||
|
||||
if (!knex) {
|
||||
knex = Knex(this.getTenantKnexConfig(organizationId));
|
||||
knexCache.set(organizationId, knex);
|
||||
}
|
||||
return knex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
exports.up = function (knex) {
|
||||
return knex.schema.createTable('users', (table) => {
|
||||
table.increments();
|
||||
table.string('first_name');
|
||||
table.string('last_name');
|
||||
table.string('email').unique();
|
||||
table.string('phone_number').unique();
|
||||
table.string('password');
|
||||
table.boolean('active');
|
||||
table.integer('role_id').unique();
|
||||
table.string('language');
|
||||
table.date('last_login_at');
|
||||
table.integer('tenant_id').unsigned();
|
||||
table.timestamps();
|
||||
}).then(() => {
|
||||
// knex.seed.run({
|
||||
// specific: 'seed_users.js',
|
||||
// })
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function (knex) {
|
||||
return knex.schema.dropTableIfExists('users');
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
exports.up = function(knex) {
|
||||
return knex.schema.createTable('tenants', (table) => {
|
||||
table.bigIncrements();
|
||||
table.string('organization_id');
|
||||
table.timestamps();
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function(knex) {
|
||||
return knex.schema.dropTableIfExists('tenants');
|
||||
};
|
||||
4
server/src/system/models/SystemModel.js
Normal file
4
server/src/system/models/SystemModel.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import BaseModel from '@/models/Model';
|
||||
|
||||
export default class SystemModel extends BaseModel{
|
||||
}
|
||||
29
server/src/system/models/SystemOption.js
Normal file
29
server/src/system/models/SystemOption.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { mixin } from 'objection';
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
import MetableCollection from '@/lib/Metable/MetableCollection';
|
||||
|
||||
export default class Option extends mixin(SystemModel, [mixin]) {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'options';
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the model query.
|
||||
* @param {...any} args -
|
||||
*/
|
||||
static query(...args) {
|
||||
return super.query(...args).runAfter((result) => {
|
||||
if (result instanceof MetableCollection) {
|
||||
result.setModel(Option);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
static get collection() {
|
||||
return MetableCollection;
|
||||
}
|
||||
}
|
||||
39
server/src/system/models/SystemUser.js
Normal file
39
server/src/system/models/SystemUser.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Model } from 'objection';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import SystemModel from '@/system/models/SystemModel';
|
||||
|
||||
export default class SystemUser extends SystemModel {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'users';
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationship mapping.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
const Tenant = require('@/system/models/Tenant');
|
||||
|
||||
return {
|
||||
tenant: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: Tenant.default,
|
||||
join: {
|
||||
from: 'users.tenant_id',
|
||||
to: 'tenants.id',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the password of the user.
|
||||
* @param {String} password - The given password.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
verifyPassword(password) {
|
||||
return bcrypt.compareSync(password, this.password);
|
||||
}
|
||||
}
|
||||
10
server/src/system/models/Tenant.js
Normal file
10
server/src/system/models/Tenant.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import BaseModel from '@/models/Model';
|
||||
|
||||
export default class Tenant extends BaseModel {
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'tenants';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user