diff --git a/README.md b/README.md index 49b4684fa..5809be0fb 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,8 @@ In order to avoid overwriting someone elses configuration medic-conf records the * upload resources to server * upload custom translations to the server * upload privacy policies to server +* upload branding to server +* upload partners to server ## Forms diff --git a/src/fn/upload-branding.js b/src/fn/upload-branding.js new file mode 100644 index 000000000..3fa9af2c4 --- /dev/null +++ b/src/fn/upload-branding.js @@ -0,0 +1,12 @@ +const environment = require('../lib/environment'); +const uploadConfigurationDocs = require('../lib/upload-configuration-docs'); + +module.exports = { + requiresInstance: true, + execute: () => { + const configurationPath = `${environment.pathToProject}/branding.json`; + const directoryPath = `${environment.pathToProject}/branding`; + + return uploadConfigurationDocs(configurationPath, directoryPath, 'branding'); + } +}; diff --git a/src/fn/upload-partners.js b/src/fn/upload-partners.js new file mode 100644 index 000000000..4e0627339 --- /dev/null +++ b/src/fn/upload-partners.js @@ -0,0 +1,12 @@ +const environment = require('../lib/environment'); +const uploadConfigurationDocs = require('../lib/upload-configuration-docs'); + +module.exports = { + requiresInstance: true, + execute: () => { + const configurationPath = `${environment.pathToProject}/partners.json`; + const directoryPath = `${environment.pathToProject}/partners`; + + return uploadConfigurationDocs(configurationPath, directoryPath, 'partners'); + } +}; diff --git a/src/fn/upload-resources.js b/src/fn/upload-resources.js index c0701a28a..010081a1f 100644 --- a/src/fn/upload-resources.js +++ b/src/fn/upload-resources.js @@ -1,39 +1,18 @@ -const attachmentsFromDir = require('../lib/attachments-from-dir'); const environment = require('../lib/environment'); -const fs = require('../lib/sync-fs'); -const pouch = require('../lib/db'); -const { info, warn } = require('../lib/log'); -const insertOrReplace = require('../lib/insert-or-replace'); -const warnUploadOverwrite = require('../lib/warn-upload-overwrite'); +const uploadConfigurationDocs = require('../lib/upload-configuration-docs'); + +const processJson = (json) => { + return { + resources: json + }; +}; module.exports = { requiresInstance: true, - execute: async () => { - const resourcesPath = fs.path.resolve(`${environment.pathToProject}/resources.json`); - - if(!fs.exists(resourcesPath)) { - warn(`No resources file found at path: ${resourcesPath}`); - return Promise.resolve(); - } - - const doc = { - _id: 'resources', - resources: fs.readJson(resourcesPath), - _attachments: attachmentsFromDir(`${environment.pathToProject}/resources`), - }; - - const db = pouch(); - - const changes = await warnUploadOverwrite.preUploadDoc(db, doc); - if (changes) { - await insertOrReplace(db, doc); - info('Resources file uploaded'); - } else { - info('Resources file not uploaded as no changes found'); - } - - warnUploadOverwrite.postUploadDoc(doc); + execute: () => { + const configurationPath = `${environment.pathToProject}/resources.json`; + const directoryPath = `${environment.pathToProject}/resources`; - return Promise.resolve(); + return uploadConfigurationDocs(configurationPath, directoryPath, 'resources', processJson); } }; diff --git a/src/lib/main.js b/src/lib/main.js index 9cda14888..e42d87bac 100755 --- a/src/lib/main.js +++ b/src/lib/main.js @@ -25,6 +25,8 @@ const defaultActions = [ 'upload-collect-forms', 'upload-contact-forms', 'upload-resources', + 'upload-branding', + 'upload-partners', 'upload-custom-translations', 'upload-privacy-policies', ]; @@ -38,6 +40,8 @@ const defaultArchiveActions = [ 'upload-collect-forms', 'upload-contact-forms', 'upload-resources', + 'upload-branding', + 'upload-partners', 'upload-custom-translations', 'upload-privacy-policies', ]; diff --git a/src/lib/upload-configuration-docs.js b/src/lib/upload-configuration-docs.js new file mode 100644 index 000000000..6c8115b37 --- /dev/null +++ b/src/lib/upload-configuration-docs.js @@ -0,0 +1,70 @@ +const attachmentsFromDir = require('../lib/attachments-from-dir'); +const fs = require('../lib/sync-fs'); +const pouch = require('../lib/db'); +const insertOrReplace = require('../lib/insert-or-replace'); +const warnUploadOverwrite = require('../lib/warn-upload-overwrite'); +const { info, warn } = require('../lib/log'); + +function filterAttachments(attachments, settings) { + if (!attachments || !settings) { + return; + } + + const settingsStr = JSON.stringify(settings); + + return Object + .entries(attachments) + .reduce((accumulator, [key, value]) => { + if (settingsStr.indexOf(key) > -1) { + accumulator[key] = value; + } + return accumulator; + }, {}); +} + +/** + * Upload Configuration to DB's document + * @param configPath (Mandatory) String. Path to configuration json file. + * @param directoryPath (Mandatory) String. Path to directory of attachments. + * @param dbDocName (Mandatory) String. DB's document name. + * @param processJson (Optional) Function. Receives the content of configuration json and + * returns an object that is used for extending the DB's document. + * @return {Promise} + */ +module.exports = async (configPath, directoryPath, dbDocName, processJson) => { + if (!configPath && !directoryPath && !dbDocName) { + warn('Information missing: Make sure to provide the configuration file path and the directory path.'); + return Promise.resolve(); + } + + const jsonPath = fs.path.resolve(configPath); + + if (!fs.exists(jsonPath)) { + warn(`No configuration file found at path: ${jsonPath}`); + return Promise.resolve(); + } + + const json = fs.readJson(jsonPath); + const settings = processJson ? processJson(json) : json; + const attachments = attachmentsFromDir(directoryPath); + const baseDocument = { + _id: dbDocName, + _attachments: filterAttachments(attachments, settings) + }; + const doc = Object.assign({}, baseDocument, settings); + + const db = pouch(); + + const changes = await warnUploadOverwrite.preUploadDoc(db, doc); + + if (changes) { + await insertOrReplace(db, doc); + info('Configuration upload complete!'); + } else { + info('Configuration not uploaded as no changes found'); + } + + warnUploadOverwrite.postUploadDoc(doc); + + return Promise.resolve(); +}; diff --git a/test/fn/upload-branding.spec.js b/test/fn/upload-branding.spec.js new file mode 100644 index 000000000..bb840fcdf --- /dev/null +++ b/test/fn/upload-branding.spec.js @@ -0,0 +1,26 @@ +const { expect } = require('chai'); +const sinon = require('sinon'); +const rewire = require('rewire'); +const environment = require('../../src/lib/environment'); +const uploadBranding = rewire('../../src/fn/upload-branding'); + +describe('Upload Branding', () => { + afterEach(() => { + sinon.reset(); + }); + + it('should call uploadConfigurationDocs with expected parameters', async () => { + const configurationPath = `${environment.pathToProject}/branding.json`; + const directoryPath = `${environment.pathToProject}/branding`; + const dbDocName = 'branding'; + const uploadConfigurationDocs = sinon.stub().returns(Promise.resolve()); + + return uploadBranding.__with__({ uploadConfigurationDocs })(async () => { + await uploadBranding.execute(); + + expect(uploadConfigurationDocs.args[0][0]).to.equal(configurationPath); + expect(uploadConfigurationDocs.args[0][1]).to.equal(directoryPath); + expect(uploadConfigurationDocs.args[0][2]).to.equal(dbDocName); + }); + }); +}); diff --git a/test/fn/upload-partners.spec.js b/test/fn/upload-partners.spec.js new file mode 100644 index 000000000..7dc7429ff --- /dev/null +++ b/test/fn/upload-partners.spec.js @@ -0,0 +1,26 @@ +const { expect } = require('chai'); +const sinon = require('sinon'); +const rewire = require('rewire'); +const environment = require('../../src/lib/environment'); +const uploadPartners = rewire('../../src/fn/upload-partners'); + +describe('Upload Partners', () => { + afterEach(() => { + sinon.reset(); + }); + + it('should call uploadConfigurationDocs with expected parameters', async () => { + const configurationPath = `${environment.pathToProject}/partners.json`; + const directoryPath = `${environment.pathToProject}/partners`; + const dbDocName = 'partners'; + const uploadConfigurationDocs = sinon.stub().returns(Promise.resolve()); + + return uploadPartners.__with__({ uploadConfigurationDocs })(async () => { + await uploadPartners.execute(); + + expect(uploadConfigurationDocs.args[0][0]).to.equal(configurationPath); + expect(uploadConfigurationDocs.args[0][1]).to.equal(directoryPath); + expect(uploadConfigurationDocs.args[0][2]).to.equal(dbDocName); + }); + }); +}); diff --git a/test/fn/upload-resources.spec.js b/test/fn/upload-resources.spec.js new file mode 100644 index 000000000..44e08addf --- /dev/null +++ b/test/fn/upload-resources.spec.js @@ -0,0 +1,26 @@ +const { expect } = require('chai'); +const sinon = require('sinon'); +const rewire = require('rewire'); +const environment = require('../../src/lib/environment'); +const uploadResources = rewire('../../src/fn/upload-resources'); + +describe('Upload Resources', () => { + afterEach(() => { + sinon.reset(); + }); + + it('should call uploadConfigurationDocs with expected parameters', async () => { + const configurationPath = `${environment.pathToProject}/resources.json`; + const directoryPath = `${environment.pathToProject}/resources`; + const dbDocName = 'resources'; + const uploadConfigurationDocs = sinon.stub().returns(Promise.resolve()); + + return uploadResources.__with__({ uploadConfigurationDocs })(async () => { + await uploadResources.execute(); + + expect(uploadConfigurationDocs.args[0][0]).to.equal(configurationPath); + expect(uploadConfigurationDocs.args[0][1]).to.equal(directoryPath); + expect(uploadConfigurationDocs.args[0][2]).to.equal(dbDocName); + }); + }); +}); diff --git a/test/lib/upload-configuration-docs.spec.js b/test/lib/upload-configuration-docs.spec.js new file mode 100644 index 000000000..94e698d17 --- /dev/null +++ b/test/lib/upload-configuration-docs.spec.js @@ -0,0 +1,185 @@ +const { expect } = require('chai'); +const sinon = require('sinon'); +const api = require('../api-stub'); +const rewire = require('rewire'); +const uploadConfigurationDocs = rewire('../../src/lib/upload-configuration-docs'); + +describe('Upload Configuration Docs', () => { + let fs; + let warn; + let pouch; + let warnUploadOverwrite; + let insertOrReplace; + let attachmentsFromDir; + let configuration = { + title: 'ABC Company', + resources: { + greatCompany: 'greatCompany.png', + aliasCompany: 'aliasCompany.png' + } + }; + + beforeEach(() => { + api.start(); + fs = { + exists: () => true, + readJson: () => configuration, + path: { + resolve: () => 'path/configuration.json' + } + }; + warnUploadOverwrite = { + preUploadDoc: sinon.stub(), + postUploadDoc: sinon.stub() + }; + warn = sinon.stub(); + pouch = sinon.stub(); + insertOrReplace = sinon.stub(); + attachmentsFromDir = sinon.stub(); + }); + + afterEach(() => { + api.stop(); + sinon.reset(); + }); + + it('should upload configuration', async () => { + warnUploadOverwrite.preUploadDoc.returns(true); + insertOrReplace.returns(Promise.resolve()); + attachmentsFromDir.returns({ 'greatCompany.png': {} }); + + const configurationDoc = { + _id: 'configurationDoc', + title: 'ABC Company', + resources: { + greatCompany: 'greatCompany.png', + aliasCompany: 'aliasCompany.png' + }, + _attachments: { 'greatCompany.png': {} } + }; + const rewireWith = { + fs, + pouch, + attachmentsFromDir, + warnUploadOverwrite, + insertOrReplace + }; + + return uploadConfigurationDocs.__with__(rewireWith)(async () => { + await uploadConfigurationDocs('path/configuration.json', 'path/configuration', 'configurationDoc'); + + expect(attachmentsFromDir.called).to.be.true; + expect(pouch.called).to.be.true; + expect(warnUploadOverwrite.preUploadDoc.args[0][1]).to.deep.include(configurationDoc); + expect(warnUploadOverwrite.postUploadDoc.args[0][0]).to.deep.include(configurationDoc); + expect(insertOrReplace.args[0][1]).to.deep.include(configurationDoc); + }); + }); + + it('should call processJson when provided', async () => { + warnUploadOverwrite.preUploadDoc.returns(true); + insertOrReplace.returns(Promise.resolve()); + attachmentsFromDir.returns({ 'greatCompany.png': {} }); + + const configurationDoc = { + _id: 'configurationDoc', + customSection: { + title: 'ABC Company' + }, + _attachments: { 'greatCompany.png': {} } + }; + const rewireWith = { + fs, + pouch, + attachmentsFromDir, + warnUploadOverwrite, + insertOrReplace + }; + const processJson = (json) => { + return { + customSection: { title: json.title }, + resources: json.resources + }; + }; + + return uploadConfigurationDocs.__with__(rewireWith)(async () => { + await uploadConfigurationDocs('path/configuration.json', 'path/configuration', 'configurationDoc', processJson); + + expect(attachmentsFromDir.called).to.be.true; + expect(pouch.called).to.be.true; + expect(warnUploadOverwrite.preUploadDoc.args[0][1]).to.deep.include(configurationDoc); + expect(warnUploadOverwrite.postUploadDoc.args[0][0]).to.deep.include(configurationDoc); + expect(insertOrReplace.args[0][1]).to.deep.include(configurationDoc); + }); + }); + + it('should warn when paths no provided', async () => { + fs.exists = () => false; + const rewireWith = { + fs, + warn, + pouch, + attachmentsFromDir, + warnUploadOverwrite, + insertOrReplace + }; + + return uploadConfigurationDocs.__with__(rewireWith)(async () => { + await uploadConfigurationDocs('configuration.js', 'configuration', 'configuration'); + + expect(warn.called).to.be.true; + expect(attachmentsFromDir.called).to.be.false; + expect(pouch.called).to.be.false; + expect(warnUploadOverwrite.preUploadDoc.called).to.be.false; + expect(insertOrReplace.called).to.be.false; + }); + }); + + it('should warn when config file doesnt exists', async () => { + fs.exists = () => false; + const rewireWith = { + fs, + warn, + pouch, + attachmentsFromDir, + warnUploadOverwrite, + insertOrReplace + }; + + return uploadConfigurationDocs.__with__(rewireWith)(async () => { + await uploadConfigurationDocs('configuration.js', 'configuration', 'configuration'); + + expect(warn.called).to.be.true; + expect(attachmentsFromDir.called).to.be.false; + expect(pouch.called).to.be.false; + expect(warnUploadOverwrite.preUploadDoc.called).to.be.false; + expect(insertOrReplace.called).to.be.false; + }); + }); + + it('should inform when no changes detected', async () => { + warnUploadOverwrite.preUploadDoc.returns(false); + insertOrReplace.returns(Promise.resolve()); + attachmentsFromDir.returns({ image: {} }); + const info = sinon.stub(); + const rewireWith = { + fs, + info, + pouch, + attachmentsFromDir, + warnUploadOverwrite, + insertOrReplace + }; + + return uploadConfigurationDocs.__with__(rewireWith)(async () => { + await uploadConfigurationDocs('configuration.js', 'configuration', 'configuration'); + + expect(info.called).to.be.true; + expect(attachmentsFromDir.called).to.be.true; + expect(pouch.called).to.be.true; + expect(warnUploadOverwrite.preUploadDoc.called).to.be.true; + expect(warnUploadOverwrite.postUploadDoc.called).to.be.true; + expect(insertOrReplace.called).to.be.false; + }); + }); +});