presentation-service-server
Advanced tools
Comparing version 2.0.13 to 2.0.14
@@ -41,3 +41,3 @@ "use strict"; | ||
function initFakeRedis() { | ||
function initFakeRedis(config) { | ||
var fakeRedis = require("fakeredis"); | ||
@@ -44,0 +44,0 @@ fakeRedis.fast = true; |
161
lib/v1.js
@@ -7,5 +7,4 @@ "use strict"; | ||
var logger = require('winston').loggers.get('elasticsearch'); | ||
var hydrateString = require("./hydrateString"); | ||
logger.transports.console.timestamp = true; | ||
var db; | ||
@@ -33,7 +32,9 @@ var logOutput = R.curry((msg, direction, req, data) => { | ||
module.exports = function (config, db) { | ||
module.exports = function (config) { | ||
db = require('./db')(config); | ||
return { | ||
get(req, res, next) { | ||
const key = decodeURIComponent(req.path()); | ||
hydrateString(db, {}, "${" + key + "}") | ||
hydrateString({}, "${" + key + "}") | ||
.errors(logStreamExceptions(req)) | ||
@@ -89,2 +90,152 @@ .stopOnError(next) | ||
}; | ||
}; | ||
}; | ||
function hydrateString(local, string) { | ||
const splits = R.flatten(splitStringByRef(string) | ||
.map(createReferenceObject(local, 0))); | ||
const refs = splits.filter(R.is(Object)); | ||
if (refs.length === 0) return hl([splits.join("")]); | ||
return db.getMultiple(refs.map(R.prop("key"))) | ||
.flatMap(values => { | ||
return values.map((val, i) => { | ||
const obj = refs[i]; | ||
if (R.isNil(val)) { | ||
return db.listKey(obj.key, obj.before, obj.after, obj.limit) | ||
.consume((err, list, push) => { | ||
if (err) { | ||
if (err.code === 'WRONGTYPE') push(null, R.assoc("value", obj.key, obj)); | ||
else push(err); | ||
} | ||
else if (R.isEmpty(list)) { | ||
if (!R.isNil(obj.def)) push(null, R.assoc("value", obj.def, obj)); | ||
else { | ||
push(null, R.assoc("value", null, obj)); | ||
} | ||
} | ||
else push(null, R.assoc("value", '[' + list.toString() + ']', obj)); | ||
push(null, hl.nil); | ||
}); | ||
} else { | ||
return hl([R.assoc("value", val, obj)]); | ||
} | ||
}); | ||
}) | ||
.sequence() | ||
.map(hydrateProps) | ||
// if the value doesnt exist, throw. Otherwise make sure is stringified | ||
.map(obj => { | ||
if (R.isNil(obj.value)) throw new restify.ResourceNotFoundError([obj.key].concat(obj.props).reverse().join(' of ') + ' not available'); | ||
else { | ||
const value = R.is(String, obj.value) ? obj.value : JSON.stringify(obj.value); | ||
if (obj.key === value) return "${" + value + "}"; | ||
local[obj.key] = value; | ||
return value; | ||
} | ||
}) | ||
.reduce(splits, populateArrayWithValues) | ||
.flatMap(function (x) { | ||
return hydrateString(local, x.join("")); | ||
}); | ||
} | ||
// if the reference contained "props" (i.e. ${ref,prop1,prop2} fill these values | ||
function hydrateProps(obj) { | ||
if (obj.props.length) { | ||
try { | ||
return R.assoc("value", R.path(obj.props, JSON.parse(obj.value)), obj); | ||
} catch (e) { | ||
return obj; | ||
} | ||
} else { | ||
return obj; | ||
} | ||
} | ||
// stitch back the string array, replacing the references with the hydrated values | ||
function populateArrayWithValues(acc, x) { | ||
const index = R.findIndex(R.is(Object))(acc); | ||
acc[index] = x; | ||
return acc; | ||
} | ||
// for each reference, replaces it with an object that can be used in the refs array | ||
const createReferenceObject = R.curry((local, i, x) => { | ||
if (R.test(/\$\{/, x)) { | ||
return R.pipe(removeRefTag, sanitizeKey, checkLocalStorage(local, i))(x); | ||
} | ||
return x; | ||
}); | ||
// check that the value hasn't already been used in the hydration process | ||
const checkLocalStorage = R.curry((local, i, obj) => { | ||
if (i > 25) { | ||
throw new restify.InternalServerError('cycle detected'); | ||
} | ||
else if (R.has(obj.key, local)) { | ||
// recursive function | ||
return splitStringByRef(local[obj.key]) | ||
.map(createReferenceObject(local, i + 1)); | ||
} | ||
else if (local[obj.key] === {}) { | ||
// if the key has ben tested previously and doesn't exist don't test again | ||
if (R.isNil(obj.def)) throw new restify.ResourceNotFoundError(obj.key + ' not available'); | ||
return obj.def; | ||
} | ||
else { | ||
return obj; | ||
} | ||
}); | ||
// splits a string into a array that splits references from the string. | ||
// The list remains in order. i.e: string === splitStringByRef(string).join(""); | ||
function splitStringByRef(string) { | ||
const newStringReplaced = string.split(/(?=[$])/) | ||
.map(inner => { | ||
if (inner.charAt(0) === "$" && inner.charAt(1) === "{") { | ||
const parentheseAt = inner.indexOf('}') + 1; | ||
return R.pair(inner.substr(0, parentheseAt), inner.substr(parentheseAt)); | ||
} | ||
return inner; | ||
}); | ||
return R.flatten(newStringReplaced); | ||
} | ||
function sanitizeKey(input) { | ||
const $temp = input.split(';'); | ||
const xs = $temp[0].split(','); | ||
var key = R.head(xs); // the db key to get the value from | ||
var before = NaN; | ||
var after = NaN; | ||
var limit = Infinity; | ||
const beforeAfterMatch = key.match(/\[(-?\d*)\|(-?\d*)\]/); | ||
if (beforeAfterMatch) { | ||
key = key.replace(beforeAfterMatch[0], ''); | ||
after = parseInt(beforeAfterMatch[1]); | ||
before = parseInt(beforeAfterMatch[2]); | ||
} | ||
const limitMatch = key.match(/\^(\d+)/); | ||
if (limitMatch) { | ||
key = key.replace(limitMatch[0], ''); | ||
limit = parseInt(limitMatch[1]); | ||
} | ||
if (Number.isNaN(before) || R.isNil(before)) before = Infinity; | ||
if (Number.isNaN(after) || R.isNil(before)) after = -Infinity; | ||
return { | ||
"key": key, | ||
"def": $temp[1], | ||
"props": R.tail(xs), | ||
"after": after, | ||
"before": before, | ||
"limit": limit | ||
}; | ||
} | ||
function removeRefTag(input) { | ||
const m = input.match(/\${(.*?)}/); | ||
return m ? m[1] : input; | ||
} |
{ | ||
"name": "presentation-service-server", | ||
"version": "2.0.13", | ||
"version": "2.0.14", | ||
"description": "Server component for the presentation service", | ||
@@ -5,0 +5,0 @@ "main": "server.js", |
@@ -5,3 +5,3 @@ "use strict"; | ||
module.exports = function (config) { | ||
module.exports = function(config) { | ||
var R = require('ramda'); | ||
@@ -18,6 +18,4 @@ var restify = require('restify'); | ||
var redisClient = require('./lib/db')(config); | ||
function useAPI(prefix, server) { | ||
var api = require('./lib/' + prefix)(config, redisClient); | ||
var api = require('./lib/' + prefix)(config); | ||
for (var method in api) { | ||
@@ -32,2 +30,3 @@ if (api.hasOwnProperty(method) && R.contains(translateAPIMethodName(method), config.allowedMethods)) { | ||
server = restify.createServer(); | ||
server.use(morgan(':date[iso] - info: endpoint method=:method, url=:url, status=:status, response-time=:response-time')); | ||
@@ -58,8 +57,7 @@ | ||
}); | ||
}; | ||
if (require.main === module) { | ||
if(require.main === module) { | ||
module.exports(require('config')); | ||
} |
@@ -5,2 +5,3 @@ "use strict"; | ||
var chai = require('chai'); | ||
var assert = chai.assert; | ||
var restify = require('restify'); | ||
@@ -7,0 +8,0 @@ var sinon = require('sinon'); |
@@ -18,8 +18,6 @@ "use strict"; | ||
var db = require("../lib/db")(config); | ||
var v1Module = rewire('../lib/v1'); | ||
var v1 = v1Module(config); | ||
var db = v1Module.__get__("db"); | ||
var v1Module = require('../lib/v1'); | ||
var v1 = v1Module(config, db); | ||
var hydrateKey = require('../lib/hydrateString'); | ||
function deleteAndSetDb(type, values) { | ||
@@ -32,5 +30,6 @@ return db.delKey(values[0]) | ||
var hydrateKey = v1Module.__get__('hydrateString'); | ||
it('should pluck values which are plain string', (done) => { | ||
deleteAndSetDb("setKey", ["key", "value"]) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.equal(value, 'value')) | ||
@@ -43,3 +42,3 @@ .pull(done) | ||
.flatMap(db.addToKey("key", 1, "value2")) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.equal(value, '[value1,value2]')) | ||
@@ -54,3 +53,3 @@ .pull(done) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.equal(value, 'duplicates, duplicates')) | ||
@@ -62,3 +61,3 @@ .pull(done); | ||
db.delKey("key") | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.pull((err, data) => { | ||
@@ -76,3 +75,3 @@ assert.notOk(data); | ||
.flatMap(db.setKey("area", "world")) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.equal(value, 'hello world')) | ||
@@ -85,3 +84,3 @@ .pull(done) | ||
.flatMap(db.delKey("area")) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.equal(value, 'hello nothing')) | ||
@@ -94,3 +93,3 @@ .pull(done) | ||
.flatMap(db.delKey("area")) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.equal(value, 'hello null')) | ||
@@ -104,3 +103,3 @@ .pull(done) | ||
.flatMap(db.setKey("place", "world")) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.equal(value, 'welcome to my world')) | ||
@@ -122,3 +121,3 @@ .pull(done) | ||
.merge() | ||
.flatMap(hydrateKey(db, {}, '${long-list}')) | ||
.flatMap(hydrateKey({}, '${long-list}')) | ||
.tap(value => assert.equal(value, expected.substring(0, expected.length - 1) + "]")) | ||
@@ -152,3 +151,3 @@ .pull(done) | ||
it("runs hydrateKey", done => { | ||
hydrateKey(db, {}, '${live-centre-list}') | ||
hydrateKey({}, '${live-centre-list}') | ||
.tap(value => assert.equal(value, expected.substring(0, expected.length - 1) + "]")) | ||
@@ -184,3 +183,3 @@ .pull(done) | ||
it("runs hydrateKey", done => { | ||
hydrateKey(db, {}, '${list}') | ||
hydrateKey({}, '${list}') | ||
//.tap(console.log) | ||
@@ -195,3 +194,3 @@ .pull(done) | ||
.flatMap(deleteAndSetDb("setKey", ["steps", '{"one": "write a fan-fiction", "two": { "three": "make movie of it"} }'])) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.equal(value, 'step 1: write a fan-fiction, step 2: make movie of it, step 3: Profit')) | ||
@@ -204,3 +203,3 @@ .pull(done) | ||
.flatMap(deleteAndSetDb("setKey", ["area", "{}"])) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.pull((err, data) => { | ||
@@ -220,3 +219,3 @@ assert.notOk(data); | ||
.flatMap(deleteAndSetDb("setKey", ["timePeriod", "day"])) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.equal(value, 'hello world, it is such a great day')) | ||
@@ -229,3 +228,3 @@ .pull(done) | ||
.flatMap(deleteAndSetDb("setKey", ["foo", '{"man": "${bar,a;}", "choo": "${bar,b;}" }'])) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.map(value => assert.deepEqual(JSON.parse(value), {man: '', choo: ''})) | ||
@@ -237,3 +236,3 @@ .pull(done) | ||
deleteAndSetDb("setKey", ["key", "this is some text which has a $sign in it like when talking about $100 bills n stuff"]) | ||
.flatMap(hydrateKey(db, {}, "${key}")) | ||
.flatMap(hydrateKey({}, "${key}")) | ||
.map(value => assert.equal(value, "this is some text which has a $sign in it like when talking about $100 bills n stuff")) | ||
@@ -246,3 +245,3 @@ .pull(done); | ||
deleteAndSetDb("setKey", ["key", "${key}"]) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.pull((err, data) => { | ||
@@ -260,3 +259,3 @@ assert.notOk(data); | ||
.flatMap(deleteAndSetDb("setKey", ["value", "${key}"])) | ||
.flatMap(hydrateKey(db, {}, '${key}')) | ||
.flatMap(hydrateKey({}, '${key}')) | ||
.pull((err, data) => { | ||
@@ -273,7 +272,16 @@ assert.notOk(data); | ||
var sinon = require("sinon"); | ||
var edgeDb = require("../lib/db"); | ||
var edgeV1 = rewire('../lib/v1'); | ||
var edgeHydrateString = edgeV1.__get__("hydrateString"); | ||
edgeDb.getMultiple = sinon.stub(); | ||
edgeDb.listKey = sinon.stub(); | ||
edgeV1.__set__("db", { | ||
"getMultiple": sinon.stub(), | ||
"listKey": sinon.stub() | ||
}); | ||
edgeV1.__set__("db", { | ||
"getMultiple": sinon.stub(), | ||
"listKey": sinon.stub() | ||
}); | ||
var edgeDb = edgeV1.__get__("db"); | ||
edgeDb.getMultiple.onCall(0).returns(hl([[null]])); | ||
@@ -288,3 +296,3 @@ edgeDb.getMultiple.onCall(1).returns(hl([["data"]])); | ||
it("should loop back if get a wrongType error", (done) => { | ||
hydrateKey(edgeDb, {}, "${key}") | ||
edgeHydrateString({}, "${key}") | ||
.pull((err, res) => { | ||
@@ -291,0 +299,0 @@ assert.equal(res, "data"); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
31091
11
723
1