sails-hook-adminjs-panel
Version:
SailsJS hook to use magic of AdminJS seamlessly
215 lines (190 loc) • 7.29 kB
JavaScript
/**
* Module dependencies
*/
const requiredHooks = [
'blueprints',
'http',
'orm',
'policies',
'views'
];
const AdminBroExpress = require('@admin-bro/express');
const express = require('express');
const AdminBro = require('admin-bro');
const WaterlineAdapter = require('./adapter/waterlineAdapter');
const path = require('path');
const defaultsObj = require('./lib/config/defaults');
const fs = require('fs');
AdminBro.registerAdapter(WaterlineAdapter);
const injectCrsfIfRequired = (originalResponse, request, context) => {
if (sails.config.security.csrf) {
//Inject csrf token if possible
const csrf = request && request.csrfToken && request.csrfToken();
originalResponse.record.params._csrf = csrf;
}
return originalResponse
}
function autoBindSailsModels(sails) {
const resources = [];
if (sails
&& sails.hooks
&& sails.hooks.orm
&& sails.hooks.orm.models) {
const models = sails.hooks.orm.models;
Object.entries(models).forEach(([key, value]) => {
const prototype = Object.getPrototypeOf(value);
resources.push({
resource: prototype,
options: {
actions: {
edit: { after: [injectCrsfIfRequired] },
delete: { after: [injectCrsfIfRequired] },
bulkDelete: { after: [injectCrsfIfRequired] },
new: { after: [injectCrsfIfRequired] }
},
},
});
});
}
return resources;
}
function ensureDirectoryExistence(filePath) {
var dirname = path.dirname(filePath);
if (fs.existsSync(dirname)) {
return true;
}
ensureDirectoryExistence(dirname);
fs.mkdirSync(dirname);
}
module.exports = function (sails) {
return {
defaults: defaultsObj,
initialize: async function (cb) {
sails.log.info('Initializing adminBroJS hook... (sails-hook-adminbrojs)');
// Check if configuration file is present, otherwise copy it
try {
const configFilePath = path.join(__dirname, '../../../config/adminjsPanel.js');
const exists = fs.existsSync(configFilePath);
if (!exists) {
ensureDirectoryExistence(configFilePath);
await fs.copyFile(path.join(__dirname, 'lib/config/defaults.js'), configFilePath, () => {});
sails.log.info('[Sails Hook][adminJSPanel] : Success Adding the configuration file.');
} else {
sails.log.info('[Sails Hook][adminJSPanel] : Configuration file already present.');
}
} catch (err) {
sails.log.error(err);
}
// Check if js files presents, otherwise copy it
try {
const configFilePath = path.join(__dirname, '../../../assets/adminJSPanel/adminbro.js');
const exists = fs.existsSync(configFilePath);
if (!exists) {
ensureDirectoryExistence(configFilePath);
await fs.copyFile(path.join(__dirname, 'lib/config/adminbro.js'), configFilePath, () => { });
sails.log.info('[Sails Hook][adminJSPanel] : Success Adding the adminJSPanel javascript file.');
} else {
sails.log.info('[Sails Hook][adminJSPanel] : adminJSPanel javascript file already present.');
}
} catch (err) {
sails.log.error(err);
}
// Check if css files presents, otherwise copy it
try {
const configFilePath = path.join(__dirname, '../../../assets/adminJSPanel/adminbro.css');
const exists = fs.existsSync(configFilePath);
if (!exists) {
ensureDirectoryExistence(configFilePath);
await fs.copyFile(path.join(__dirname, 'lib/config/adminbro.css'), configFilePath, () => { });
sails.log.info('[Sails Hook][adminJSPanel] : Success Adding the adminJSPanel CSS file.');
} else {
sails.log.info('[Sails Hook][adminJSPanel] : adminJSPanel CSS file already present.');
}
} catch (err) {
sails.log.error(err);
}
const { routes, assets } = AdminBro.Router;
sails.on('router:before', () => {
const sailsModels = autoBindSailsModels(sails);
const adminBro = new AdminBro({
database: [],
resources: sails.config.adminJSPanel.parseResources(sailsModels),
rootPath: sails.config.adminJSPanel.rootPath,
dashboard: {
component: AdminBro.bundle('./lib/react/my-dashboard-component')
},
assets: {
styles: ['/adminJSPanel/adminbro.css'],
scripts: ['/adminJSPanel/adminbro.js'],
},
branding: {
companyName: 'AdminJS-Panel',
softwareBrothers: false,
logo: '/images/logo.png',
},
...(sails.config.adminJSPanel.adminJSOptions ?? {}),
});
const rootPath = adminBro.options.rootPath || '/admin';
routes.forEach((route) => {
const handler = async function (req, res, next) {
const controller = new route.Controller({ admin: adminBro }, req.session && req.session.adminUser);
const {
params, query } = req;
const method = req.method.toLowerCase();
//req.body Contains the form fields. Lets parse them in payload. Better approach is to use formdible but to try it later on
const payload = Object.assign(Object.assign({}, (req.fields || {})), (req.files || {}), (req.body || {}));
const controllerParams = Object.assign(Object.assign({}, req), {
params,
query,
payload,
method
});
const html = await controller[route.action](controllerParams, res);
if (route.contentType) {
res.set({ 'Content-Type': route.contentType });
}
res.set({ 'Some-Info': 'Arnios, Okan Kurtulus' });
if (html) {
res.send(html);
}
};
const authCheckedHandler = async function(req, res, next) {
return sails.config.adminJSPanel.auth(req, res, () => {
handler(req, res, next);
});
}
const routerPath = `${rootPath}${route.path}`;
// we have to change routes defined in AdminBro from {recordId} to :recordId
const expressPath = routerPath.replace(/{/g, ':').replace(/}/g, '');
const routePath = `${route.method} ${expressPath}`;
sails.router.bind(expressPath, authCheckedHandler, route.method);
sails.config.routes[routePath] = { csrf: false };
});
assets.forEach((asset) => {
const routerPath = `${rootPath}${asset.path}`;
const expressPath = routerPath.replace(/{/g, ':').replace(/}/g, '');
const routePath = `GET ${expressPath}`;
sails.router.bind(routePath, async (req, res) => {
res.sendFile(path.resolve(asset.src));
});
});
});
return cb();
},
configure: function () {
sails.log.info('Configure function is working for (sails-hook-adminbrojs)');
},
routes: {
before: {
'GET /*': function (req, res, next) {
return next();
},
},
after: {
'GET /*': function (req, res, next) {
return next();
},
},
}
};
};