From 3594729d142af0d5a65e5e6254273be77705d817 Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Sat, 27 Jun 2015 16:42:10 +0100 Subject: [PATCH] Get helper closes #4439 - adds get helper + tests --- core/server/helpers/get.js | 106 ++++++++++++++++++++++ core/server/helpers/index.js | 2 + core/test/unit/server_helpers/get_spec.js | 63 +++++++++++++ package.json | 1 + 4 files changed, 172 insertions(+) create mode 100644 core/server/helpers/get.js create mode 100644 core/test/unit/server_helpers/get_spec.js diff --git a/core/server/helpers/get.js b/core/server/helpers/get.js new file mode 100644 index 000000000000..5ebfe156ee31 --- /dev/null +++ b/core/server/helpers/get.js @@ -0,0 +1,106 @@ +// # Get Helper +// Usage: `{{#get "posts" limit="5"}}`, `{{#get "tags" limit="all"}}` +// Fetches data from the API + +var _ = require('lodash'), + hbs = require('express-hbs'), + errors = require('../errors'), + api = require('../api'), + jsonpath = require('jsonpath'), + + resources = ['posts', 'tags', 'users'], + pathAliases = { + 'post.tags': 'post.tags[*].slug', + 'post.author': 'post.author.slug' + }, + get; + +function doBrowse(context, options) { + var browse = true; + if (options.limit && options.limit === 1) { + browse = false; + } + + if (options.id || options.slug) { + browse = false; + } + + return browse; +} + +function resolvePaths(data, value) { + var regex = /\{\{(.*?)\}\}/g; + + value = value.replace(regex, function (match, path) { + var result; + + // Handle tag, author and role aliases + path = pathAliases[path] ? pathAliases[path] : path; + + result = jsonpath.query(data, path); + + if (_.isArray(result)) { + result = result.join(','); + } + + return result; + }); + + return value; +} + +function parseOptions(data, options) { + options = _.omit(options.hash, 'context'); + if (_.isArray(options.tag)) { + options.tag = _.pluck(options.tag, 'slug').join(','); + } + + if (_.isString(options.filter)) { + options.filter = resolvePaths(data, options.filter); + } + + return options; +} + +get = function get(context, options) { + options = options || {}; + options.hash = options.hash || {}; + + var self = this, + data, + apiOptions, + apiMethod; + + if (!_.contains(resources, context)) { + errors.logWarn('Invalid resource given to get helper'); + return; + } + + if (options.data) { + data = hbs.handlebars.createFrame(options.data); + } + + // Determine if this is a read or browse + apiMethod = doBrowse(context, options) ? api[context].browse : api[context].read; + // Parse the options we're going to pass to the API + apiOptions = parseOptions(this, options); + + return apiMethod(apiOptions).then(function success(result) { + var data = _.merge(self, result); + if (_.isEmpty(result[context])) { + return options.inverse(self); + } + + return options.fn(data, { + data: data, + blockParams: [result[context]] + }); + }).catch(function error(err) { + if (data) { + data.error = err.message; + } + return options.inverse(self, {data: data}); + }); +}; + +module.exports = get; diff --git a/core/server/helpers/index.js b/core/server/helpers/index.js index 5f75a3c97d38..3fae2935d72d 100644 --- a/core/server/helpers/index.js +++ b/core/server/helpers/index.js @@ -21,6 +21,7 @@ coreHelpers.date = require('./date'); coreHelpers.encode = require('./encode'); coreHelpers.excerpt = require('./excerpt'); coreHelpers.foreach = require('./foreach'); +coreHelpers.get = require('./get'); coreHelpers.ghost_foot = require('./ghost_foot'); coreHelpers.ghost_head = require('./ghost_head'); coreHelpers.image = require('./image'); @@ -117,6 +118,7 @@ registerHelpers = function (adminHbs) { registerAsyncThemeHelper('post_class', coreHelpers.post_class); registerAsyncThemeHelper('next_post', coreHelpers.next_post); registerAsyncThemeHelper('prev_post', coreHelpers.prev_post); + registerAsyncThemeHelper('get', coreHelpers.get); // Register admin helpers registerAdminHelper('asset', coreHelpers.asset); diff --git a/core/test/unit/server_helpers/get_spec.js b/core/test/unit/server_helpers/get_spec.js new file mode 100644 index 000000000000..946ab95f3460 --- /dev/null +++ b/core/test/unit/server_helpers/get_spec.js @@ -0,0 +1,63 @@ +/*globals describe, before, beforeEach, afterEach, it*/ +/*jshint expr:true*/ +var should = require('should'), + sinon = require('sinon'), + hbs = require('express-hbs'), + Promise = require('bluebird'), + utils = require('./utils'), + +// Stuff we are testing + handlebars = hbs.handlebars, + helpers = require('../../../server/helpers'), + api = require('../../../server/api'); + +describe('{{#get}} helper', function () { + var sandbox; + + before(function () { + utils.loadHelpers(); + }); + + beforeEach(function () { + sandbox = sinon.sandbox.create(); + }); + + afterEach(function () { + sandbox.restore(); + }); + + it('has loaded get block helper', function () { + should.exist(handlebars.helpers.get); + }); + + describe('posts', function () { + var testPostsObj = { + posts: [ + {id: 1} + ] + }; + beforeEach(function () { + sandbox.stub(api.posts, 'browse', function () { + return Promise.resolve(testPostsObj); + }); + }); + + it('should handle default posts call', function (done) { + var fn = sinon.spy(), + inverse = sinon.spy(); + + helpers.get.call( + {}, + 'posts', + {hash: {}, fn: fn, inverse: inverse} + ).then(function () { + fn.called.should.be.true; + fn.firstCall.args[0].should.be.an.Object; + fn.firstCall.args[0].should.eql(testPostsObj); + inverse.called.should.be.false; + + done(); + }).catch(done); + }); + }); +}); diff --git a/package.json b/package.json index acf20d53f29b..fce36f0c9045 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "html-to-text": "1.3.0", "intl": "1.0.0", "intl-messageformat": "1.1.0", + "jsonpath": "0.1.8", "knex": "0.7.3", "lodash": "3.10.0", "moment": "2.10.3",