Some basic components for building forms.

This commit is contained in:
Tomas Bures 2017-06-04 13:16:29 +02:00
parent d13fc65ce2
commit 4504d539c5
22 changed files with 827 additions and 246 deletions

11
lib/InteroperableError.js Normal file
View file

@ -0,0 +1,11 @@
'use strict';
class InteroperableError extends Error {
constructor(type, msg, data) {
super(msg);
this.type = type;
this.data = data;
}
}
module.exports = InteroperableError;

View file

@ -23,7 +23,8 @@ module.exports = {
injectCustomFormTemplates,
filterCustomFields,
getMjmlTemplate,
rollbackAndReleaseConnection
rollbackAndReleaseConnection,
filterObject
};
function getDefaultMergeTags(callback) {
@ -293,3 +294,14 @@ function rollbackAndReleaseConnection(connection, callback) {
return callback();
});
}
function filterObject(obj, allowedKeys) {
const result = {};
for (const key in obj) {
if (allowedKeys.has(key)) {
result[key] = obj[key];
}
}
return result;
}

View file

@ -1,5 +1,76 @@
'use strict';
const knex = require('../knex');
const hasher = require('node-object-hash')();
const { filterObject } = require('../helpers');
const InteroperableError = require('../InteroperableError');
module.exports.list = () => knex('namespaces');
class ChangedError extends InteroperableError {
constructor(msg, data) {
super('namespaces.ChangedError', msg, data);
}
}
class NotFoundError extends InteroperableError {
constructor(msg, data) {
super('namespaces.NotFoundError', msg, data);
}
}
const allowedKeys = new Set(['id', 'name', 'description', 'parent']);
const allowedUpdateKeys = new Set(['name', 'description', 'parent']);
async function list() {
return await knex('namespaces');
}
function hash(ns) {
return hasher.hash(filterObject(ns, allowedKeys));
}
async function getById(nsId) {
const ns = await knex('namespaces').where('id', nsId).first();
if (!ns) {
throw new NotFoundError();
}
ns.hash = hash(ns);
return ns;
}
async function create(ns) {
const nsId = await knex('namespaces').insert(filterObject(ns, allowedKeys));
return nsId;
}
async function updateWithConsistencyCheck(ns) {
await knex.transaction(async tx => {
const existingNs = await tx('namespaces').where('id', ns.id).first();
if (!ns) {
throw new NotFoundError();
}
const existingNsHash = hash(existingNs);
if (existingNsHash != ns.originalHash) {
throw new ChangedError();
}
tx('namespaces').where('id', ns.id).update(filterObject(ns, allowedUpdateKeys));
});
}
async function remove(nsId) {
await knex('namespaces').where('id', nsId).del();
}
module.exports = {
NotFoundError,
ChangedError,
hash,
list,
getById,
create,
updateWithConsistencyCheck,
remove
};

View file

@ -1,6 +1,7 @@
'use strict';
const express = require('express');
const InteroperableError = require('./InteroperableError');
function safeHandler(handler) {
return function(req, res) {
@ -8,12 +9,45 @@ function safeHandler(handler) {
};
}
function safeJSONHandler(handler) {
return function(req, res) {
handler(req, res).catch(error => {
const resp = {
message: error.message
};
if (error instanceof InteroperableError) {
resp.type = error.type;
resp.data = error.data;
}
res.status(500).json(resp);
});
};
}
function replaceLast(elems, replaceFn) {
if (elems.length === 0) {
return elems;
}
const lastElem = elems[elems.size - 1];
const replacement = replaceFn(lastElem);
elems[elems.size - 1] = replacement;
return elems;
}
function create() {
const router = new express.Router();
router.getAsync = (path, asyncFn) => router.get(path, safeHandler(asyncFn));
router.getAsync = (path, ...handlers) => router.get(path, ...replaceLast(handlers, safeHandler));
router.postAsync = (path, asyncFn) => router.post(path, safeHandler(asyncFn));
router.getAsyncJSON = (path, ...handlers) => router.get(path, ...replaceLast(handlers, safeJSONHandler));
router.postAsyncJSON = (path, ...handlers) => router.post(path, ...replaceLast(handlers, safeJSONHandler));
router.putAsyncJSON = (path, ...handlers) => router.put(path, ...replaceLast(handlers, safeJSONHandler));
router.deleteAsyncJSON = (path, ...handlers) => router.delete(path, ...replaceLast(handlers, safeJSONHandler));
return router;
}