Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,22 @@
// ║╣ ╚═╗║ ║║║║ ║ ├┬┘│
// o╚═╝╚═╝╩═╝╩╝╚╝ ╩ ┴└─└─┘
// A set of basic code conventions designed to encourage quality and consistency
// across your Sails app's code base. These rules are checked against
// automatically any time you run `npm test`.
// across your app's code base. These rules are checked against automatically
// any time you run `npm test`.
//
// > Note: If you're using mocha, you'll want to add an extra override file to your
// > `test/` folder so that eslint will tolerate mocha-specific globals like `before`
// > and `describe`.
// Designed for ESLint v4.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// For more information about any of the rules below, check out the relevant
// reference page on eslint.org. For example, to get details on "no-sequences",
// you would visit `http://eslint.org/docs/rules/no-sequences`. If you're unsure
// or could use some advice, come by https://sailsjs.com/support.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
module.exports = {
env: {
node: true,
es6: true,
},

parserOptions: {
ecmaVersion: 8,
ecmaVersion: 2020,
},

root: true,
Expand All @@ -46,5 +42,19 @@ module.exports = {

// eslint rule customization here:
"no-console": 0, // allow console.log() in our services
"no-unused-vars": 0, // allow unused variables (webpack will remove them)
},

globals: {
AB: true, // global ABFactory
io: true, // socket.io
reports: true, // webix's Report Manager widget
tinymce: true,
Selectivity: true,
webix: true, // webix
gantt: true,
$$: true, // webix element
scheduler: true,
_: true,
},
};
2 changes: 1 addition & 1 deletion .github/workflows/build-ecs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ jobs:
name: Build
uses: CruGlobal/.github/.github/workflows/build-ecs.yml@v1
with:
microservice-app: appbuilder
microservice-app: ab_service_api_sails
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ ARG BRANCH=master

FROM digiserve/service-cli:${BRANCH}

COPY . /app
COPY ./package* /app/

WORKDIR /app

RUN npm i -f

COPY . /app

CMD ["node", "--inspect=0.0.0.0:9229", "app.js"]
77 changes: 67 additions & 10 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,20 @@
const fs = require("fs");
const path = require("path");
const process = require("process");
const splitSqlByDelimiter = require("./util/splitSql");

const AB = require("@digiserve/ab-utils");

const Mysql = require("mysql"); // our {DB Connection}
const config = require(path.join(__dirname, "config", "local.js"));
// {json}
// our current set of configuration options for connecting to our DB
const site = config.datastores.site;
// We might not have an admin tenant database configured yet so don't try to
// connect to it
delete site.database;

const DB = Mysql.createConnection(config.datastores.site);
const DB = Mysql.createConnection(site);
DB.on("error", (err) => {
tLog("DB.on(error):", err);

Expand Down Expand Up @@ -141,8 +146,7 @@ function ReadTenants() {
// ridden in the req.connections().site.database setting.

let conn = req.connections();
if (conn.site?.database)
tenantDB = `\`${conn.site.database}\``;
if (conn.site?.database) tenantDB = `\`${conn.site.database}\``;
tenantDB += ".";

let sql = `SELECT * FROM ${tenantDB}\`site_tenant\` `;
Expand Down Expand Up @@ -217,11 +221,11 @@ function doCommand(list, req, cb) {
}
}

function tenantProcessPatch(req, fileName) {
function tenantProcessPatch(req, fileName, directory = "patches") {
return new Promise((resolve, reject) => {
let filePath = path.join(__dirname, "patches", fileName);
let filePath = path.join(__dirname, directory, fileName);
let contents = fs.readFileSync(filePath, { encoding: "utf8" });
let commands = contents.split(";");
let commands = splitSqlByDelimiter(contents);
doCommand(commands, req, (err) => {
if (err) {
reject(err);
Expand All @@ -234,9 +238,13 @@ function tenantProcessPatch(req, fileName) {

function tenantPostLastPatch(req, lastPatch) {
return new Promise((resolve, reject) => {
let sql =
'UPDATE `SITE_CONFIG` SET `value` = ? WHERE `key` = "migration-last-patch";';
req.queryIsolate(sql, [lastPatch], (err, results /*, fields */) => {
let sql = [
"LOCK TABLES `SITE_CONFIG` WRITE",
`UPDATE \`SITE_CONFIG\` SET \`value\` = "${lastPatch}" WHERE \`key\` = "migration-last-patch"`,
"UNLOCK TABLES",
];
doCommand(sql, req, (err) => {
// req.queryIsolate(sql, [lastPatch], (err, results /*, fields */) => {
if (err) {
console.log(err);
reject(err);
Expand Down Expand Up @@ -282,7 +290,8 @@ async function ProcessTenant(id) {
}
tenantReq.queryIsolateClose();
if (error) {
if (currPatch != lastPatch) tLog(id, `completed up until patch ${lastPatch}`);
if (currPatch != lastPatch)
tLog(id, `completed up until patch ${lastPatch}`);
throw error;
}
tLog(id, "tenant migration complete.");
Expand Down Expand Up @@ -319,6 +328,51 @@ async function PullPatchFiles() {
});
}

/**
* Checks if a database with a specific name exists.
* @param {string} dbName - The name of the database to check for.
* @returns {Promise<boolean>} A promise that resolves to true if the database exists, false otherwise.
*/
function dbExists(dbName = "appbuilder-admin") {
console.log("Checking for db:", dbName);
return new Promise((resolve, reject) => {
DB.query("SHOW DATABASES", (err, rows) => {
if (err) {
return reject(err);
}
const exists = rows.some((row) => row.Database === dbName);
// Temporary code to fix a partial init
if (exists) {
DB.query(
"SHOW TABLES FROM `appbuilder-admin` LIKE 'site_tenant'",
(_, rows) => {
if (rows.length > 0) {
resolve(true);
} else resolve(false);
}
);
} else {
resolve(exists);
}
});
});
}

/**
* Add the appbuilder-admin database and base site tables / definitions
*/
async function initDB() {
console.log("No `appbuilder-admin` database found. Initializing...");
const initDir = path.join(__dirname, "init");
const sqlFiles = fs.readdirSync(initDir);
const req = new AB.reqService(mockReq(), mockController());
for (const sqlFile of sqlFiles) {
console.log(`applying ${sqlFile}`);
await tenantProcessPatch(req, sqlFile, "init");
}
console.log("Done initilizing `appbuilder-admin`");
}

//
// Now we just wait to be closed out when the docker stack is removed.
function wait() {
Expand All @@ -329,6 +383,9 @@ async function Do() {
try {
await PullPatchFiles();
await Connect();
if (!(await dbExists())) {
await initDB();
}
let tenantIDs = await ReadTenants();
console.log(`${tenantIDs.length} tenants to process.`);

Expand Down
3 changes: 3 additions & 0 deletions init/01-CreateDBs.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# create databases
CREATE DATABASE IF NOT EXISTS `appbuilder` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE IF NOT EXISTS `appbuilder-admin` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
55 changes: 55 additions & 0 deletions init/02-tenant_manager.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ************************************************************
# Sequel Pro SQL dump
# Version 4541
#
# http://www.sequelpro.com/
# https://github.com/sequelpro/sequelpro
#
# Host: 127.0.0.1 (MySQL 5.5.5-10.4.11-MariaDB-1:10.4.11+maria~bionic)
# Database: site
# Generation Time: 2020-01-03 09:25:33 +0000
# ************************************************************


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

USE `appbuilder-admin`;

# Dump of table site_tenant
# ------------------------------------------------------------

DROP TABLE IF EXISTS `site_tenant`;

CREATE TABLE `site_tenant` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`properties` longtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `uuid` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

LOCK TABLES `site_tenant` WRITE;
/*!40000 ALTER TABLE `site_tenant` DISABLE KEYS */;

INSERT INTO `site_tenant` (`id`, `uuid`, `key`, `properties`)
VALUES
(1,'admin','admin','{ \"title\":\"Tenant Admin\", \"authType\":\"login\", \"url\":\"https://[tenantKey].site.url\" }');

/*!40000 ALTER TABLE `site_tenant` ENABLE KEYS */;
UNLOCK TABLES;



/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Loading
Loading