diff --git a/lib/responses.js b/lib/responses.js index 51321100..6a0b5909 100644 --- a/lib/responses.js +++ b/lib/responses.js @@ -7,7 +7,9 @@ var db = require('./services/db'), const _ = require('lodash'), bluebird = require('bluebird'), filter = require('through2-filter'), - metaController = require('./services/metadata'); + { getPrefix } = require('clayutils'), + metaController = require('./services/metadata'), + siteService = require('./services/sites'); /** * Finds prefixToken, and removes it and anything before it. @@ -17,11 +19,12 @@ const _ = require('lodash'), * @returns {string} */ function removePrefix(str, prefixToken) { - const index = str.indexOf(prefixToken); + const index = str.indexOf(prefixToken); if (index > -1) { str = str.substr(index + prefixToken.length).trim(); } + return str; } @@ -489,7 +492,12 @@ function getRouteFromDB(req, res) { */ function putRouteFromDB(req, res) { expectJSON(function () { - return db.put(req.uri, JSON.stringify(req.body)).then(() => req.body); + const { uri, body } = req, + prefix = getPrefix(uri), + site = siteService.getSiteFromPrefix(prefix), + putData = { data: body, siteSlug: site.slug }; + + return db.put(uri, JSON.stringify(putData)).then(() => body); }, res); } diff --git a/lib/routes/_uris.js b/lib/routes/_uris.js index a2a293ef..a7840655 100644 --- a/lib/routes/_uris.js +++ b/lib/routes/_uris.js @@ -24,7 +24,7 @@ function getUriFromReference(req, res) { * @param {object} res */ function putUriFromReference(req, res) { - responses.expectText(() => controller.put(req.uri, req.body), res); + responses.expectText(() => controller.put(req.uri, req.body, res.locals), res); } /** diff --git a/lib/services/pages.js b/lib/services/pages.js index 51e78a08..ea2a56e5 100644 --- a/lib/services/pages.js +++ b/lib/services/pages.js @@ -154,20 +154,6 @@ function getRecursivePublishedPutOperations(locals) { }; } -/** - * Given either locals or a string, - * return the site we're working with - * - * @param {String} prefix - * @param {Object} locals - * @returns {Object} - */ -function getSite(prefix, locals) { - const site = locals && locals.site; - - return site || siteService.getSiteFromPrefix(prefix); -} - /** * Cannot contain any empty value (null, '', undefined, false) * @param {object} data @@ -206,13 +192,14 @@ function getPublishData(uri, data) { * @param {string} sitePrefix * @param {string} publicUrl * @param {string} pageUri + * @param {string} slug */ -function addOpToMakePublic(ops, sitePrefix, publicUrl, pageUri) { +function addOpToMakePublic({ ops, sitePrefix, publicUrl, pageUri, slug }) { // make public ops.push({ type: 'put', key: `${sitePrefix}/_uris/${buf.encode(references.urlToUri(publicUrl))}`, - value: replaceVersion(pageUri) + value: { data: replaceVersion(pageUri), siteSlug: slug } }); } @@ -226,14 +213,14 @@ function addOpToMakePublic(ops, sitePrefix, publicUrl, pageUri) { function publish(uri, data, locals) { const startTime = process.hrtime(), prefix = getPrefix(uri), - site = getSite(prefix, locals), + site = siteService.getSiteFromLocals(prefix, locals) || {}, timeoutLimit = timeoutConstant * timeoutPublishCoefficient, user = locals && locals.user; var publishedMeta; // We need to store some meta a little later return getPublishData(uri, data) .then(publishService.resolvePublishUrl(uri, locals, site)) - .then(({ meta, data: pageData}) => { + .then(({ meta, data: pageData }) => { const published = 'published', dynamicPage = pageData._dynamic, componentList = references.getPageReferences(pageData); @@ -248,16 +235,24 @@ function publish(uri, data, locals) { // convert the data to all @published pageData = replacePageReferenceVersions(pageData, published); + const putData = { data: pageData, siteSlug: site.slug }; + // Make public unless we're dealing with a `_dynamic` page if (!dynamicPage) { - addOpToMakePublic(ops, prefix, meta.url, uri); + addOpToMakePublic({ + ops, + sitePrefix: prefix, + publicUrl: meta.url, + pageUri: uri, + slug: site.slug + }); } // Store the metadata if we're at this point publishedMeta = meta; // add page PUT operation last - return addOp(replaceVersion(uri, published), pageData, ops); + return addOp(replaceVersion(uri, published), putData, ops); }); }) .then(applyBatch) @@ -274,11 +269,11 @@ function publish(uri, data, locals) { .then(publishedData => { return meta.publishPage(uri, publishedMeta, user).then(() => { // Notify the bus - bus.publish('publishPage', { uri, data: publishedData, user}); + bus.publish('publishPage', { uri, data: publishedData.data, user}); - notifications.notify(site, 'published', publishedData); + notifications.notify(site, 'published', publishedData.data); // Update the meta object - return publishedData; + return publishedData.data; }); }); } @@ -294,6 +289,7 @@ function create(uri, data, locals) { const layoutReference = data && data.layout, pageData = data && references.omitPageConfiguration(data), prefix = getPrefix(uri), + site = siteService.getSiteFromLocals(prefix, locals) || {}, pageReference = `${prefix}/_pages/${uid.get()}`, user = locals && locals.user; @@ -306,18 +302,21 @@ function create(uri, data, locals) { return getPageClonePutOperations(pageData, locals) .then(ops => { pageData.layout = layoutReference; - return addOp(pageReference, pageData, ops); + + const putData = { data: pageData, siteSlug: site.slug }; + + return addOp(pageReference, putData, ops); }); }) .then(applyBatch) .then(newPage => { - newPage._ref = pageReference; + newPage.data._ref = pageReference; - return meta.createPage(newPage._ref, user) + return meta.createPage(newPage.data._ref, user) .then(() => { - bus.publish('createPage', { uri: pageReference, data: newPage, user }); + bus.publish('createPage', { uri: pageReference, data: newPage.data, user }); - return newPage; + return newPage.data; }); }); } @@ -332,7 +331,10 @@ function create(uri, data, locals) { * @returns {Promise} */ function putLatest(uri, data, locals) { - const user = locals && locals.user; + const user = locals && locals.user, + prefix = getPrefix(uri), + site = siteService.getSiteFromLocals(prefix, locals) || {}, + putData = { data, siteSlug: site.slug }; // check the page for a proper layout if (!data.layout || !isLayout(data.layout)) { @@ -341,12 +343,12 @@ function putLatest(uri, data, locals) { // continue saving the page normally return db.getLatestData(uri) - .then(() => db.put(uri, JSON.stringify(data)).then(() => data)) // data already exist + .then(() => db.put(uri, JSON.stringify(putData)).then(() => putData)) // data already exist .catch(() => { - return db.put(uri, JSON.stringify(data)) + return db.put(uri, JSON.stringify(putData)) .then(() => meta.createPage(uri, user)) .then(() => { - bus.publish('createPage', { uri, data, user }); + bus.publish('createPage', { uri, data: putData.data, user }); return data; }); diff --git a/lib/services/pages.test.js b/lib/services/pages.test.js index abae556f..903f5289 100644 --- a/lib/services/pages.test.js +++ b/lib/services/pages.test.js @@ -31,6 +31,7 @@ describe(_.startCase(filename), function () { sandbox.stub(components, 'get'); sandbox.stub(layouts, 'get'); sandbox.stub(siteService, 'getSiteFromPrefix'); + sandbox.stub(siteService, 'getSiteFromLocals'); sandbox.stub(notifications, 'notify'); sandbox.stub(dbOps); sandbox.stub(timer); @@ -72,7 +73,7 @@ describe(_.startCase(filename), function () { .then(result => { expect(result._ref).to.match(/^domain.com\/path\/_pages\//); delete result._ref; - expect(result).to.deep.equal({layout: 'domain.com/path/_layouts/thing'}); + expect(result).to.deep.equal({layout: 'domain.com/path/_layouts/thing' }); }); }); @@ -113,7 +114,8 @@ describe(_.startCase(filename), function () { const fn = lib[this.title], locals = { site: { - resolvePublishUrl: [] + resolvePublishUrl: [], + slug: 'nymag' } }; @@ -133,6 +135,7 @@ describe(_.startCase(filename), function () { data: pageData })); meta.publishPage.returns(Promise.resolve()); + siteService.getSiteFromLocals.returns(locals.site); return fn('domain.com/path/_pages/thing@published', pageData, locals) .then(() => { @@ -142,7 +145,7 @@ describe(_.startCase(filename), function () { expect(secondLastOp).to.deep.equal({ type: 'put', key: 'domain.com/path/_uris/c29tZS1kb21haW4uY29tLw==', - value: 'domain.com/path/_pages/thing' + value: { data: 'domain.com/path/_pages/thing', siteSlug: 'nymag' } }); }); }); @@ -163,18 +166,18 @@ describe(_.startCase(filename), function () { data: pageData })); meta.publishPage.returns(Promise.resolve()); - siteService.getSiteFromPrefix.returns(locals.site); + siteService.getSiteFromLocals.returns(locals.site); return fn('domain.com/path/_pages/thing@published', pageData, {}) .then(() => { const ops = db.batch.args[0][0], secondLastOp = ops[ops.length - 2]; - sinon.assert.calledOnce(siteService.getSiteFromPrefix); + sinon.assert.calledOnce(siteService.getSiteFromLocals); expect(secondLastOp).to.deep.equal({ type: 'put', key: 'domain.com/path/_uris/c29tZS1kb21haW4uY29tLw==', - value: 'domain.com/path/_pages/thing' + value: { data: 'domain.com/path/_pages/thing', siteSlug: 'nymag' } }); }); }); diff --git a/lib/services/sites.js b/lib/services/sites.js index 17c42284..2be46694 100644 --- a/lib/services/sites.js +++ b/lib/services/sites.js @@ -131,12 +131,27 @@ function getSiteFromPrefix(prefix) { return site; // Return the site } +/** + * Given either locals or a string, + * return the site we're working with + * + * @param {String} prefix + * @param {Object} locals + * @returns {Object} + */ +function getSiteFromLocals(prefix, locals) { + const site = locals && locals.site; + + return site || getSiteFromPrefix(prefix); +} + module.exports.sites = _.memoize(getSites); module.exports.get = getSite; module.exports.getSite = getSite; module.exports.getSiteFromPrefix = getSiteFromPrefix; +module.exports.getSiteFromLocals = getSiteFromLocals; // exported for tests module.exports.normalizePath = normalizePath; module.exports.normalizeDirectory = normalizeDirectory; -module.exports.setLog = mock => log = mock; \ No newline at end of file +module.exports.setLog = mock => log = mock; diff --git a/lib/services/sites.test.js b/lib/services/sites.test.js index c7bc33ed..6de88b2b 100644 --- a/lib/services/sites.test.js +++ b/lib/services/sites.test.js @@ -272,4 +272,23 @@ describe(_.startCase(filename), function () { expect(fn(path.sep + ['some', path.sep, 'path'].join('') + path.sep)).to.equal(normalized); }); }); + + describe('getSiteFromLocals', function () { + const fn = lib[this.title], + locals = { + site: { + slug: 'nymag' + } + }; + + it('returns site data from locals object', function () { + expect(fn('', locals)).to.equal(locals.site); + }); + + it('returns site data from prefix', function () { + sandbox.stub(lib, 'sites').returns(mockSites); + + expect(fn('h/i/j')).to.equal(mockSites.c); + }); + }); }); diff --git a/lib/services/uris.js b/lib/services/uris.js index 546564ac..8dc02e74 100644 --- a/lib/services/uris.js +++ b/lib/services/uris.js @@ -13,9 +13,10 @@ var db = require('./db'); /** * @param {string} uri * @param {string} body + * @param {Object} locals * @returns {Promise} */ -function put(uri, body) { +function put(uri, body, locals) { if (uri === body) { throw new Error('Client: Cannot point uri at itself'); } @@ -28,7 +29,11 @@ function put(uri, body) { throw new Error('Client: Cannot point uri at propagating version, such as @published'); } - return db.put(uri, body).then(() => body); + const prefix = getPrefix(uri), + site = siteService.getSiteFromLocals(prefix, locals), + putData = { data: body, siteSlug: site.slug }; + + return db.put(uri, JSON.stringify(putData)).then(() => body); } /** diff --git a/test/api/_pages/put.js b/test/api/_pages/put.js index a087e0f5..138849d5 100644 --- a/test/api/_pages/put.js +++ b/test/api/_pages/put.js @@ -36,7 +36,7 @@ describe(endpointName, function () { url: 'http://localhost.example.com', layout: `localhost.example.com/_layouts/layout@${version}`, center: `localhost.example.com/_components/valid@${version}`, - side: [`localhost.example.com/_components/valid@${version}`] + side: [`localhost.example.com/_components/valid@${version}`], }; }, versionedDeepData = function (version) {