@knapsack/app
Version:
Build Design Systems on top of knapsack, by Basalt
600 lines (533 loc) • 15.8 kB
JavaScript
;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getApiRoutes = getApiRoutes;
var _express = _interopRequireDefault(require("express"));
var _urlJoin = _interopRequireDefault(require("url-join"));
var _marked = _interopRequireDefault(require("marked"));
var _fsExtra = _interopRequireDefault(require("fs-extra"));
var _path = require("path");
var _child_process = require("child_process");
var _highlight = _interopRequireDefault(require("highlight.js"));
var _changeCase = require("change-case");
var _shortid = _interopRequireDefault(require("shortid"));
var _multer = _interopRequireDefault(require("multer"));
var Files = _interopRequireWildcard(require("../schemas/api/files"));
var _plugins = require("../schemas/api/plugins");
var _plugins2 = require("./api/plugins");
var _memDb = require("./dbs/mem-db");
var log = _interopRequireWildcard(require("../cli/log"));
var _constants = require("../lib/constants");
var _auth = require("./auth");
var _serverUtils = require("./server-utils");
var _features = require("../lib/features");
/**
* Copyright (C) 2018 Basalt
This file is part of Knapsack.
Knapsack is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
Knapsack is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along
with Knapsack; if not, see <https://www.gnu.org/licenses>.
*/
const router = _express.default.Router();
const memDb = new _memDb.MemDb(); // https://marked.js.org/#/USING_ADVANCED.md
_marked.default.setOptions({
highlight: code => _highlight.default.highlightAuto(code).value
});
function getApiRoutes({
registerEndpoint,
patternManifest,
pageBuilder,
settingsStore,
meta,
baseUrl,
tokens,
config
}) {
router.get(baseUrl, (req, res) => {
res.json({
ok: true,
message: 'Welcome to the API!'
});
});
router.post(_plugins.endpoint, _plugins2.handlePluginsEndpoint);
{
const url = (0, _urlJoin.default)(baseUrl, 'data');
registerEndpoint(url, 'POST');
router.post(url, async (req, res) => {
const {
body,
headers
} = req;
if (headers['content-type'] !== 'application/json') {
res.send({
ok: false,
message: "Must send with a Header of 'Content-Type: application/json'"
});
return;
}
const hash = memDb.addData(body);
res.send({
ok: true,
message: `Data has been made and can be viewed with hash "${hash}"`,
data: {
hash
}
});
});
}
if (patternManifest) {
async function render({
patternId,
templateId,
demoId,
assetSetId,
isInIframe,
dataId
}) {
if (demoId && dataId) {
const message = `Cannot send query params "demoId" and "dataId" to render endpont for pattern "${patternId}", template "${templateId}"`;
log.error(message, {
patternId,
templateId,
demoId,
assetSetId,
isInIframe,
dataId
});
return {
ok: false,
html: `<p>${message}</p>`,
wrappedHtml: `<p>${message}</p>`,
message,
dataId: ''
};
}
const demo = dataId ? memDb.getData(dataId) : demoId; // log.inspect({ demoId, demo });
try {
const results = patternManifest.render({
patternId,
templateId,
demo,
isInIframe,
websocketsPort: meta.websocketsPort,
assetSetId // demoDataId,
});
return results;
} catch (e) {
return {
ok: false,
html: `<p>${e.message}</p>`,
wrappedHtml: `<p>${e.message}</p>`,
message: e.message,
dataId: ''
};
}
}
const url = (0, _urlJoin.default)(baseUrl, '/render');
registerEndpoint(url, 'GET');
registerEndpoint(url, 'POST');
router.post(url, async (req, res) => {
const {
body
} = req;
const {
patternId,
templateId,
isInIframe,
assetSetId,
demoId,
dataId
} = body;
if (!(patternId && templateId)) {
res.send({
ok: false,
message: `Missing patternId or templateId in body`,
data: body
});
} else {
const results = await render({
patternId,
templateId,
isInIframe,
assetSetId,
demoId,
dataId
});
res.send(results);
}
});
router.get(url, async (req, res) => {
const {
query
} = req;
query.wrapHtml = query.wrapHtml === 'true';
query.isInIframe = query.isInIframe === 'true';
const {
patternId,
templateId,
isInIframe,
wrapHtml,
assetSetId,
demoId,
dataId
} = query;
const results = await render({
patternId,
templateId,
assetSetId,
dataId,
demoId,
isInIframe
});
if (results.ok) {
res.send(wrapHtml ? results.wrappedHtml : results.html);
} else {
let demo;
if (dataId) {
demo = memDb.getData(dataId);
}
log.error(`Error rendering template`, {
patternId,
templateId,
dataId,
wrapHtml,
isInIframe,
assetSetId,
message: results.message,
demo
});
console.log(); // empty line
res.send(results.message);
}
});
}
if (patternManifest) {
const url1 = (0, _urlJoin.default)(baseUrl, 'pattern/:id');
registerEndpoint(url1);
router.get(url1, async (req, res) => {
const results = await patternManifest.getPattern(req.params.id);
res.send(results);
});
const url2 = (0, _urlJoin.default)(baseUrl, 'patterns');
registerEndpoint(url2);
router.get(url2, async (req, res) => {
const results = await patternManifest.getPatterns();
res.send(results);
});
{
const url = Files.endpoint;
registerEndpoint(url);
router.post(url, async (req, res) => {
const userInfo = (0, _auth.getUserInfo)(req);
const {
isLocalDev
} = (0, _features.getFeaturesForUser)(userInfo);
const localOnly = () => res.status(_constants.HTTP_STATUS.BAD.BAD_REQUEST).send({
ok: false,
message: 'This endpoint only available to local developers'
});
let response;
const reqBody = req.body;
const {
data: dataDir
} = config;
switch (reqBody.type) {
case Files.ACTIONS.verify:
{
if (!isLocalDev) {
return localOnly();
}
const {
path
} = reqBody.payload;
const {
exists,
absolutePath,
type
} = (0, _serverUtils.resolvePath)({
path,
resolveFromDirs: [dataDir]
});
response = {
type: Files.ACTIONS.verify,
payload: {
exists,
relativePath: exists ? (0, _path.relative)(dataDir, absolutePath) : '',
absolutePath,
type
}
};
break;
}
case Files.ACTIONS.saveTemplateDemo:
{
if (!isLocalDev) {
return localOnly();
}
const {
patternId,
templateId,
demoId,
code
} = reqBody.payload;
const fullPath = patternManifest.getTemplateDemoAbsolutePath({
patternId,
templateId,
demoId
});
try {
await _fsExtra.default.writeFile(fullPath, code, 'utf8');
response = {
type: Files.ACTIONS.saveTemplateDemo,
payload: {
ok: true
}
};
} catch (e) {
response = {
type: Files.ACTIONS.saveTemplateDemo,
payload: {
ok: false,
message: e.message
}
};
}
break;
}
case Files.ACTIONS.deleteTemplateDemo:
{
if (!isLocalDev) {
return localOnly();
}
const {
path
} = reqBody.payload;
const {
exists,
absolutePath
} = (0, _serverUtils.resolvePath)({
path,
resolveFromDirs: [dataDir]
});
if (!exists) {
response = {
type: Files.ACTIONS.deleteTemplateDemo,
payload: {
ok: false,
message: 'File already did not exist'
}
};
} else {
try {
await _fsExtra.default.remove(absolutePath);
response = {
type: Files.ACTIONS.deleteTemplateDemo,
payload: {
ok: true
}
};
} catch (e) {
log.error('Files.ACTIONS.deleteTemplateDemo', e, '/api/files');
response = {
type: Files.ACTIONS.deleteTemplateDemo,
payload: {
ok: false,
message: e.message
}
};
}
}
break;
}
case Files.ACTIONS.openFile:
{
if (!isLocalDev) {
return localOnly();
}
const {
filePath
} = reqBody.payload;
const {
exists,
absolutePath
} = (0, _serverUtils.resolvePath)({
path: filePath,
resolveFromDirs: [dataDir]
});
if (exists) {
(0, _child_process.exec)(`open ${absolutePath}`, err => {
if (err) log.error(`error opening file: ${err.message}`, {
filePath,
err
});
response = {
type: Files.ACTIONS.openFile,
payload: {
ok: !err,
message: err ? err.message : ''
}
};
});
}
}
}
res.send(response);
});
}
}
if (pageBuilder) {
const url1 = (0, _urlJoin.default)(baseUrl, `${_constants.BASE_PATHS.PAGE_BUILDER}/:id`);
registerEndpoint(url1);
router.get(url1, async (req, res) => {
try {
const page = await pageBuilder.getPageBuilderPage(req.params.id);
res.send({
ok: true,
page
});
} catch (error) {
if (error.code === 'ENOENT') {
res.send({
ok: false,
message: `Example "${req.params.id}" not found.`
});
} else {
res.send({
ok: false,
message: error.toString()
});
}
}
});
const url2 = (0, _urlJoin.default)(baseUrl, `${_constants.BASE_PATHS.PAGE_BUILDER}/:id`);
registerEndpoint(url2, 'POST');
router.post(url2, async (req, res) => {
const results = await pageBuilder.setPageBuilderPage(req.params.id, req.body);
res.send(results);
});
const url3 = (0, _urlJoin.default)(baseUrl, _constants.BASE_PATHS.PAGE_BUILDER);
registerEndpoint(url3);
router.get(url3, async (req, res) => {
const results = await pageBuilder.getPageBuilderPages();
res.send(results);
});
} else {
router.get((0, _urlJoin.default)(baseUrl, _constants.BASE_PATHS.PAGE_BUILDER), async (req, res) => {
res.send([]);
});
}
const url3 = (0, _urlJoin.default)(baseUrl, 'settings');
registerEndpoint(url3);
router.get(url3, async (req, res) => {
const settings = settingsStore.getData();
res.send(settings);
});
const url4 = (0, _urlJoin.default)(baseUrl, 'design-tokens');
registerEndpoint(url4);
router.get(url4, (req, res) => {
res.send(tokens.getTokens());
});
const url5 = (0, _urlJoin.default)(baseUrl, 'meta');
registerEndpoint(url5);
router.get(url5, (req, res) => {
res.send(meta);
});
{
const url = (0, _urlJoin.default)(baseUrl, 'loading');
registerEndpoint(url);
router.get(url, (req, res) => {
res.send(`<p>Loading...</p>`);
});
}
const url6 = (0, _urlJoin.default)(baseUrl, 'permissions');
registerEndpoint(url6);
router.get(url6, (req, res) => {
const {
role
} = (0, _auth.getUserInfo)(req);
res.send(role.permissions);
});
const destination = (0, _path.join)(config.public, 'uploads');
const uploaderLocal = (0, _multer.default)({
dest: config.public,
storage: _multer.default.diskStorage({
destination,
filename(req, file, cb) {
const {
originalname
} = file;
const {
name,
ext
} = (0, _path.parse)(originalname);
let filename = `${(0, _changeCase.paramCase)(name)}${ext}`;
if (_fsExtra.default.existsSync((0, _path.join)(destination, filename))) {
filename = `${(0, _changeCase.paramCase)(name)}-${_shortid.default.generate()}${ext}`;
}
cb(null, filename);
}
})
});
const uploadLocalSingle = uploaderLocal.single('file');
const url7 = (0, _urlJoin.default)(baseUrl, 'upload');
registerEndpoint(url7);
router.post(url7, (req, res) => {
let resData;
uploadLocalSingle(req, res, err => {
const {
file
} = req;
if (err instanceof _multer.default.MulterError) {
resData = {
ok: false,
message: err.message
};
return res.send(resData);
}
if (err) {
resData = {
ok: false,
message: err.message
};
return res.send(resData);
}
if (!file) {
resData = {
ok: false,
message: 'Did not receive a file'
};
return res.send(resData);
}
const {
path,
size,
mimetype,
originalname,
filename
} = file;
const publicPath = `/${(0, _path.relative)(config.public, path)}`;
resData = {
ok: true,
data: {
publicPath,
size,
mimetype,
originalName: originalname,
filename
}
};
return res.status(200).send(resData);
});
});
return router;
}