UNPKG

@knapsack/app

Version:

Build Design Systems on top of knapsack, by Basalt

600 lines (533 loc) • 15.8 kB
"use strict"; 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; }