WIP Multi-tenant architecture.

This commit is contained in:
Ahmed Bouhuolia
2020-04-21 22:47:27 +02:00
parent 4e0d3feebe
commit 8f588ffc51
64 changed files with 812 additions and 447 deletions

View 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;
}
}

View File

@@ -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');
};

View File

@@ -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');
};

View File

@@ -0,0 +1,4 @@
import BaseModel from '@/models/Model';
export default class SystemModel extends BaseModel{
}

View 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;
}
}

View 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);
}
}

View File

@@ -0,0 +1,10 @@
import BaseModel from '@/models/Model';
export default class Tenant extends BaseModel {
/**
* Table name.
*/
static get tableName() {
return 'tenants';
}
}