diff --git a/README.md b/README.md index 0a69e5afd..a701bcd25 100644 --- a/README.md +++ b/README.md @@ -1,110 +1,102 @@ -history -======= - -Your personal **history** storyboarded with photo and video albums. Associate photos with their meta data including geocode, caption, friends (characters)... in XML albums. -* Plot thumbnails on a map -* Code runs on static web hosts -* Includes administration tools for XML generation -* Free & open source (dependant on other open source projects see indiviual licenses) - -[Demo site 0.15.0](http://danactive.github.io/history/) - - -Basic Demo Usage ------- - -* Clone this repository. -* Open Index.htm in Firefox. -* Click View Photo Galleries. -* Click Sample. -* From there it becomes more obvious. - -Technologies ------- -####Viewing -* XML databases for photo/video galleries -* XSLT to transform XML to HTML/CSS/JavaScript/jQuery -* JavaScript/jQuery for the pagination & lightbox - -####Administration -* Node.js to support AJAX & image manipulation -* AJAX to read the XML gallery data - - -Dependancies ------- -Included in this project -* [jQuery](http://jquery.com/) via bower -* [ColorBox (jQuery plugin)](http://www.jacklmoore.com/colorbox) via bower -* [Mapstraction (mapping)](http://mapstraction.com/) build 2.0.18 -* [Google Maps (map provider)](https://developers.google.com/maps/) v3 -* [Twitter Bootstrap (admin)](http://twitter.github.com/bootstrap/) v2.0.3 -* [Fluid 960 Grid System (admin)](http://www.designinfluences.com/fluid960gs/) - -To use the administration tools -* [node.js](http://nodejs.org/) -* [hapi.js](http://hapijs.org/) -* [GraphicsMagick](https://www.npmjs.com/package/gm) Install GraphicsMagick before npm -* [bower](http://bower.io/) via npm - * npm install -g bower - -Folder structures -------- -* admin/ - administration files for generating XML. Copy and paste the XML structure into the albums -* gallery-demo/ - demonstration of a gallery with the sample album inside -* node_modules/ - Backup of installed modules for Node.js -* .gitignore - blacklist files/folders for GitHub -* README.md - this file -* index.htm - Home page when avoiding Node.js -* video.htm - Reads a query string and generates the HTML5 video tags -* app.js - Node.js code for creating a web server -* webserver_node START.bat - (Windows) Executes the Node.js web server for localhost viewing and administration image manipulation -* webserver_node VIEW.url - (Windows) Opens http://localhost in default browser - -Photo/video album XML schemas -------- -### Current schema (2.0) - -Example - - - - demo - sample - 1.8 - - - 1 - 2001-03-21-01.jpg - - 49.25 - -123.1 - - Vancouver, BC - Granville Island - An oversized avocado - Lunch - - - 1 - 2012-fireplace.mp4 - 2012-fireplace.webm - Vancouver, BC - Home - Video: Fireplace - A sample HTML5 video in both MP4 and WebM formats - 1280720 - - 49.25 - -123.1 - - - - -License -------- -History is open-source and released under the [BSD License.](http://www.opensource.org/licenses/bsd-license.php) - -Versioning -------- -http://semver.org/ +history +======= + +Your personal **history** storyboarded with photo and video albums. Associate photos with their meta data including geocode, caption, friends (characters)... in XML albums. +* Plot thumbnails on a map +* Code runs on static web hosts +* Includes administration tools for XML generation +* Free & open source (dependant on other open source projects see indiviual licenses) + +[Demo site 0.15.0](http://danactive.github.io/history/) + + +Basic Demo Usage +------ + +* Clone this repository. +* Open Index.htm in Firefox. +* Click View Photo Galleries. +* Click Sample. +* From there it becomes more obvious. + +Technologies +------ +####Viewing +* XML databases for photo/video galleries +* XSLT to transform XML to HTML/CSS/JavaScript/jQuery +* JavaScript/jQuery for the pagination & lightbox + +####Administration +* Node.js to support AJAX & image manipulation +* AJAX to read the XML gallery data + + +Dependancies +------ +Included in this project +* [jQuery](http://jquery.com/) via bower +* [ColorBox (jQuery plugin)](http://www.jacklmoore.com/colorbox) via bower +* [Mapstraction (mapping)](http://mapstraction.com/) build 2.0.18 +* [Google Maps (map provider)](https://developers.google.com/maps/) v3 +* [Twitter Bootstrap (admin)](http://twitter.github.com/bootstrap/) v2.0.3 +* [Fluid 960 Grid System (admin)](http://www.designinfluences.com/fluid960gs/) + +To use the administration tools +* [node.js](http://nodejs.org/) +* [hapi.js](http://hapijs.org/) +* [GraphicsMagick](https://www.npmjs.com/package/gm) Install GraphicsMagick before npm +* [bower](http://bower.io/) via npm + * npm install -g bower + +Folder structures +------- +* admin/ - administration files for generating XML. Copy and paste the XML structure into the albums +* gallery-demo/ - demonstration of a gallery with the sample album inside +* node_modules/ - Backup of installed modules for Node.js +* .gitignore - blacklist files/folders for GitHub +* README.md - this file +* index.htm - Home page when avoiding Node.js +* video.htm - Reads a query string and generates the HTML5 video tags +* app.js - Node.js code for creating a web server +* webserver_node START.bat - (Windows) Executes the Node.js web server for localhost viewing and administration image manipulation +* webserver_node VIEW.url - (Windows) Opens http://localhost in default browser + +Photo/video album XML schemas +------- +### Current schema (2.0) + +Example + + + + demo + sample + 1.8 + + + 1 + 2001-03-21-01.jpg + + 49.25 + -123.1 + + Vancouver, BC + Granville Island + An oversized avocado + Lunch + + + 1 + 2012-fireplace.mp4 + 2012-fireplace.webm + Vancouver, BC + Home + Video: Fireplace + A sample HTML5 video in both MP4 and WebM formats + 1280720 + + 49.25 + -123.1 + + + diff --git a/changelog.md b/changelog.md index b89850b79..764d61301 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,14 @@ # Changelog +### 1.3.0 - hapi plugins for exists and rename +#### 2016-Feb-09 +* Exist green code coverage +* Rename green code coverage +* Dev-mode no gulp + +### 1.2.0 - hapi.js v12 +#### 2016-Jan-30 + ### 1.1.0 - Up-to-date and passes #### 2016-Jan-24 * All tests pass @@ -75,4 +84,4 @@ * Sample album with three Vancouver markers on map * jQuery v1.7.2 * Mapstraction Build 2.0.18 - pre-release using Google Maps v3 -* ColorBox v1.3.19 \ No newline at end of file +* ColorBox v1.3.19 diff --git a/package.json b/package.json index 18f22842d..3f98ecc62 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "gulp-mocha": "^2.2.0", "gulp-plumber": "^1.0.1", "gulp-rename": "^1.2.0", + "lout": "^8.1.1", "node-notifier": "^4.1.2" }, "scripts": { @@ -67,9 +68,8 @@ }, "homepage": "https://github.com/danactive/history", "engines": { - "node": ">=0.10.35" + "npm": ">3" }, "readmeFilename": "README.md", - "tuxharness": "./tuxharness.js", - "engines" : { "npm" : ">3" } + "tuxharness": "./tuxharness.js" } diff --git a/plugins/exists/lib/index.js b/plugins/exists/lib/index.js index ddc98225b..f1f0f0c2d 100644 --- a/plugins/exists/lib/index.js +++ b/plugins/exists/lib/index.js @@ -1,35 +1,23 @@ 'use strict'; -/* -* ####### -* # # # # #### ##### #### -* # # # # # # # -* ##### ## # #### # #### -* # ## # # # # -* # # # # # # # # # -* ####### # # # #### # #### -* -*/ /** Verify if a path exists on the file system -@method folderExists -@param {string} path absolute path (file or folder) on the file system +@method pathExists +@param {string} path relative/absolute path (file or folder) on the file system @param {promise} **/ -function folderExists(verifyPath) { +function pathExists(verifyPath) { return new Promise((resolve, reject) => { - const fs = require('fs'); - const appRoot = require('app-root-path'); - let verifiedPath = verifyPath; - - if (verifyPath.charAt(0) === '.' || verifyPath.charAt(0) === '/') { // convert relative to absolute - verifiedPath = appRoot.resolve(verifyPath); + const boom = require('boom'); + if (verifyPath === undefined) { + reject(boom.notFound(`pathExists module: is missing a path to verify`)); } + const verifiedPath = require('path').isAbsolute(verifyPath) ? + verifyPath : require('app-root-path').resolve(verifyPath); - fs.stat(verifiedPath, (error, type) => { - const boom = require('boom'); + require('fs').stat(verifiedPath, (error, type) => { if (error) { - return reject(boom.notFound(`File system path is missing ${error}`)); + return reject(boom.notFound(`pathExists module: File system path is missing ${error}`)); } if (type.isFile() || type.isDirectory()) { return resolve(verifiedPath); @@ -37,4 +25,4 @@ function folderExists(verifyPath) { }); }); } -exports.folderExists = folderExists; +exports.pathExists = pathExists; diff --git a/plugins/exists/package.json b/plugins/exists/package.json index 5f874d50b..3d6ca888c 100644 --- a/plugins/exists/package.json +++ b/plugins/exists/package.json @@ -1,6 +1,6 @@ { "name": "history-exists", - "version": "1.2.0", + "version": "2.0.0", "description": "Verify if folder path exists", "main": "index.js", "scripts": { diff --git a/plugins/exists/test/index.js b/plugins/exists/test/index.js index 651966bc6..13792ca3d 100644 --- a/plugins/exists/test/index.js +++ b/plugins/exists/test/index.js @@ -3,30 +3,30 @@ const test = require('tape'); test('Real relative file exists', (assert) => { const module = require('../lib'); - const testFolder = './plugins/exists/test/fixtures/exists.txt'; + const testPath = './plugins/exists/test/fixtures/exists.txt'; - module.folderExists(testFolder) + module.pathExists(testPath) .then(() => { assert.pass('Resolved promise is returned'); assert.end(); }) .catch(() => { - assert.fail(`File system is missing folder (${testFolder})`); + assert.fail(`File system is missing folder (${testPath})`); assert.end(); }); }); test('Real relative folder exists', (assert) => { const module = require('../lib'); - const testFolder = './plugins/exists/test/fixtures'; + const testPath = './plugins/exists/test/fixtures'; - module.folderExists(testFolder) + module.pathExists(testPath) .then(() => { assert.pass('Resolved promise is returned'); assert.end(); }) .catch(() => { - assert.fail(`File system is missing folder (${testFolder})`); + assert.fail(`File system is missing folder (${testPath})`); assert.end(); }); }); @@ -34,15 +34,15 @@ test('Real relative folder exists', (assert) => { test('Real absolute file exists', (assert) => { const module = require('../lib'); const path = require('path'); - const testFolder = path.join(__dirname, './fixtures/exists.txt'); + const testPath = path.join(__dirname, './fixtures/exists.txt'); - module.folderExists(testFolder) + module.pathExists(testPath) .then((verifiedPath) => { - assert.equal(verifiedPath, testFolder, 'Resolved path matches'); + assert.equal(verifiedPath, testPath, 'Resolved path matches'); assert.end(); }) .catch(() => { - assert.fail(`File system is missing folder (${testFolder})`); + assert.fail(`File system is missing folder (${testPath})`); assert.end(); }); }); @@ -50,15 +50,15 @@ test('Real absolute file exists', (assert) => { test('Real absolute folder exists', (assert) => { const module = require('../lib'); const path = require('path'); - const testFolder = path.join(__dirname, './fixtures'); + const testPath = path.join(__dirname, './fixtures'); - module.folderExists(testFolder) + module.pathExists(testPath) .then((verifiedPath) => { - assert.equal(verifiedPath, testFolder, 'Resolved path matches'); + assert.equal(verifiedPath, testPath, 'Resolved path matches'); assert.end(); }) .catch(() => { - assert.fail(`File system is missing folder (${testFolder})`); + assert.fail(`File system is missing folder (${testPath})`); assert.end(); }); }); @@ -66,11 +66,11 @@ test('Real absolute folder exists', (assert) => { test('Fake absolute path does not exists', (assert) => { const module = require('../lib'); const path = require('path'); - const testFolder = path.join(__dirname, './fixtures/fakeFolder'); + const testPath = path.join(__dirname, './fixtures/fakeFolder'); - module.folderExists(testFolder) + module.pathExists(testPath) .then(() => { - assert.fail(`File system found a fake folder (${testFolder})`); + assert.fail(`File system found a fake folder (${testPath})`); assert.end(); }) .catch((error) => { diff --git a/plugins/rename/lib/index.js b/plugins/rename/lib/index.js index bc7df683a..db7be62d1 100644 --- a/plugins/rename/lib/index.js +++ b/plugins/rename/lib/index.js @@ -9,11 +9,17 @@ exports.register = (server, options, next) => { config: { handler: (request, reply) => { const filenames = request.payload.filenames; - require('../../exists/lib').folderExists(request.payload.source_folder) + require('../../exists/lib').pathExists(request.payload.source_folder) .then(() => require('./filenames').getFutureFilenames(request.payload.prefix, filenames.length)) .then((futureFilenames) => { - require('./rename').renamePaths(request.payload.source_folder, filenames, futureFilenames.filenames); - reply(futureFilenames.xml); + require('./rename').renamePaths( + request.payload.source_folder, + filenames, + futureFilenames.filenames, + { + renameAssociated: request.payload.rename_associated, + }); + reply({ xml: futureFilenames.xml }); }) .catch((error) => { let boomError; @@ -26,13 +32,24 @@ exports.register = (server, options, next) => { reply(boomError); }); }, - tags: ['api'], + tags: ['api', 'plugin', 'v1'], validate: { payload: { - filenames: joi.array().items(joi.string().regex(/^[-\w^&'@{}[\],$=!#().%+~ ]+$/)).min(1).max(80).required(), - prefix: joi.string().isoDate().required(), - source_folder: joi.string().trim().required(), - target_folder: joi.string().trim(), + filenames: joi.array().items(joi.string().regex(/^[-\w^&'@{}[\],$=!#().%+~ ]+$/)) + .min(1).max(80).required().example('["DSC01229.JPG"]'), + prefix: joi.string().isoDate().required().example('2016-12-31'), + source_folder: joi.string().trim().required().example('/public/todo/'), + rename_associated: joi.boolean().default(false) + .description(`JPG and RAW or video and still image are common ` + + `associated pairs that should rename together`), + }, + }, + response: { + schema: { + xml: joi.string().required().regex(/]*>(.*?)<\/photo>/) + .example(`2016-04-05-37.jpg` + + `2016-04-05-64.jpg` + + `2016-04-05-90.jpg`), }, }, }, diff --git a/plugins/rename/lib/rename.js b/plugins/rename/lib/rename.js index c43c80175..4f1a45f8f 100644 --- a/plugins/rename/lib/rename.js +++ b/plugins/rename/lib/rename.js @@ -1,4 +1,49 @@ 'use strict'; + +/** +Find associated path and filename based on file without extension + +@method findAssociated +@param {string} [sourceFolder] Folder that contains the raw camera photo files +@param {string} [filename] path and filename with or without extension +@return {Promise} array of string associated filenames with absolute path +**/ +function findAssociated(sourceFolder, filename) { + return new Promise((resolve, reject) => { + const path = require('path'); + const absolutePath = path.isAbsolute(sourceFolder) ? path.join(sourceFolder, filename) : + require('app-root-path').resolve(path.join('../../', sourceFolder, filename)); + const file = absolutePath.substr(0, absolutePath.length - path.extname(absolutePath).length); // strip extension + + require('glob')(`${file}.*`, (error, files) => { + if (error) { + reject(require('boom').wrap(error)); + } + resolve(files); + }); + }); +} +exports.findAssociated = findAssociated; + +/** +Reassign associated filename based on file without extension + +@method reassignAssociated +@param {string[]} [absoluteFolderFilenames] Filenames that contains the raw camera photo files with absolute path +@param {string} [futureFile] Future file (without extension) of renamed new name based on date +@return {Promise} associated filenames with path +**/ +function reassignAssociated(absoluteFolderFilenames, futureFile) { + return new Promise((resolve) => { + const path = require('path'); + resolve(absoluteFolderFilenames.map(filename => { + const fileParts = path.parse(filename); + return path.join(fileParts.dir, futureFile + fileParts.ext); + })); + }); +} +exports.reassignAssociated = reassignAssociated; + /** Renamed file paths @@ -6,38 +51,80 @@ Renamed file paths @param {string} [sourceFolder] Folder that contains the raw camera photo files @param {string[]} [filenames] Current filenames (file and extension) of raw camera photo files @param {string[]} [futureFilenames] Future filenames (file and extension) of renamed camera photo files -@return {json} +@param {object} options Additional optional options +@param {bool} options.renameAssociated Find matching files with different extensions, then rename them +@return {Promise} **/ -function renamePaths(sourceFolder, filenames, futureFilenames) { +function renamePaths(sourceFolder, filenames, futureFilenames, _options) { return new Promise((resolve, reject) => { const fs = require('fs'); const exists = require('../../exists/lib'); const boom = require('boom'); - const q = require('async').queue((rename, next) => { - exists.folderExists(rename.oldName) - .then(() => { - fs.rename(rename.oldName, rename.newName, (error) => { - if (error) { - reject(boom.wrap(error)); - } - next(); - }); - }) + const options = _options || {}; + const async = require('async'); + + const q = async.queue((rename, next) => { + function renameFile() { + fs.rename(rename.oldName, rename.newName, (error) => { + if (error) { + reject(boom.wrap(error)); + } + next(); + }); + } + exists.pathExists(rename.oldName) + .then(renameFile) .catch((error) => { reject(boom.wrap(error)); }); }, 2); + { + const path = require('path'); + const fullPath = require('app-root-path').resolve(path.join('../../', sourceFolder, '/')); + const filenamePairs = filenames.map((filename, index) => { + return { current: filename, future: futureFilenames[index] }; + }); + const transformFilenames = (pair, cb) => { + if (options.renameAssociated) { + let oldNames; + findAssociated(fullPath, pair.current) + .then(associatedFilenames => { + oldNames = associatedFilenames; + const endWithoutExt = pair.future.length - path.extname(pair.future).length; + const futureFile = pair.future.substr(0, endWithoutExt); // strip extension + return reassignAssociated(associatedFilenames, futureFile); + }) + .then(reassignFilenames => { + const reassignPairs = oldNames.map((oldName, index) => { + return { oldName, newName: reassignFilenames[index] }; + }); + return cb(null, reassignPairs); + }); + } else { + const oldName = fullPath + pair.current; + const newName = fullPath + pair.future; + + return cb(null, { oldName, newName }); + } + }; + async.map(filenamePairs, transformFilenames, (error, transformedPairs) => { + if (error) { + throw boom.wrap(error); + } + + if (Array.isArray(transformedPairs)) { + transformedPairs.forEach((pair) => { + q.push(pair); + }); + } else { + q.push(transformedPairs); + } + }); + } + // assign a callback q.drain = () => resolve(true); - - const path = require('path'); - const appRoot = require('app-root-path'); - filenames.forEach((filename, index) => { - const oldName = appRoot.resolve(path.join('../../', sourceFolder, filename)); - const newName = appRoot.resolve(path.join('../../', sourceFolder, futureFilenames[index])); - q.push({ oldName, newName }); - }); }); } exports.renamePaths = renamePaths; diff --git a/plugins/rename/package.json b/plugins/rename/package.json index c37fabba8..5001c8a78 100644 --- a/plugins/rename/package.json +++ b/plugins/rename/package.json @@ -1,6 +1,6 @@ { "name": "history-rename", - "version": "1.1.0", + "version": "2.0.0", "description": "Rename files", "main": "index.js", "scripts": { @@ -29,6 +29,7 @@ "npm": ">3" }, "dependencies": { - "app-root-path": "^1.0.0" + "app-root-path": "^1.0.0", + "glob": "^7.0.0" } } diff --git a/plugins/rename/test/fixtures/renameable/bee.bat b/plugins/rename/test/fixtures/renameable/bee.bat new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/bee.bin b/plugins/rename/test/fixtures/renameable/bee.bin new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/bee.bmp b/plugins/rename/test/fixtures/renameable/bee.bmp new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/dee.dat b/plugins/rename/test/fixtures/renameable/dee.dat new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/dee.doc b/plugins/rename/test/fixtures/renameable/dee.doc new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/dee.docx b/plugins/rename/test/fixtures/renameable/dee.docx new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/el.log b/plugins/rename/test/fixtures/renameable/el.log new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/em.md b/plugins/rename/test/fixtures/renameable/em.md new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/pee.pdf b/plugins/rename/test/fixtures/renameable/pee.pdf new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/pee.psd b/plugins/rename/test/fixtures/renameable/pee.psd new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/tee.tar b/plugins/rename/test/fixtures/renameable/tee.tar new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/fixtures/renameable/tee.tax b/plugins/rename/test/fixtures/renameable/tee.tax new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/rename/test/index.js b/plugins/rename/test/index.js index db1004830..ddbd11074 100644 --- a/plugins/rename/test/index.js +++ b/plugins/rename/test/index.js @@ -17,9 +17,9 @@ test('Verify /rename route', (assert) => { method: 'POST', url: '/rename', payload: { - filenames: ['aitch.html', 'gee.gif', 'pee.png'], + filenames: ['aitch.html', 'gee.gif', 'em.md'], prefix, - source_folder: '/rename/test/fixtures/renameable', + source_folder: './plugins/rename/test/fixtures/renameable/FAKE', }, }; server.inject(request, (result) => { @@ -40,13 +40,13 @@ test('Verify /rename route', (assert) => { method: 'POST', url: '/rename', payload: { - filenames: ['aitch.html', 'gee.gif', 'pee.png'], + filenames: ['aitch.html', 'gee.gif', 'em.md'], prefix, - source_folder: '/plugins/rename/test/fixtures/renameable', + source_folder: './plugins/rename/test/fixtures/renameable', }, }; server.inject(request, (response) => { - st.equal(response.result, `${prefix}-37.jpg` + + st.equal(response.result.xml, `${prefix}-37.jpg` + `${prefix}-64.jpg` + `${prefix}-90.jpg`); st.equal(response.statusCode, 200); @@ -58,7 +58,52 @@ test('Verify /rename route', (assert) => { assert.test('-Restore filenames to original', (st) => { setTimeout(() => { const filenames = [`${prefix}-37.jpg`, `${prefix}-64.jpg`, `${prefix}-90.jpg`]; - const futureFilenames = ['aitch.html', 'gee.gif', 'pee.png']; + const futureFilenames = ['aitch.html', 'gee.gif', 'em.md']; + const sourceFolder = './plugins/rename/test/fixtures/renameable'; + const module = require('../lib/rename'); + + module.renamePaths(sourceFolder, filenames, futureFilenames) + .then((result) => { + st.equal(result, true, 'No errors'); + st.end(); + }) + .catch((error) => { + st.fail(`Rename failed ${error}`); + st.end(); + }); + }, 1100); + }); + + assert.test('-Rename filename based on prefix with associated files', (st) => { + const server = new hapi.Server(); + server.connection({ port: 8000 }); + server.register(plugins, (error) => { + if (error) { + return st.fail(error); + } + const request = { + method: 'POST', + url: '/rename', + payload: { + filenames: ['dee.dat', 'pee.pdf'], + prefix, + source_folder: './plugins/rename/test/fixtures/renameable', + rename_associated: true, + }, + }; + server.inject(request, (response) => { + st.equal(response.result.xml, `${prefix}-50.jpg` + + `${prefix}-90.jpg`); + st.equal(response.statusCode, 200); + st.end(); + }); + }); + }); + + assert.test('-Restore filenames to original with associated files', (st) => { + setTimeout(() => { + const filenames = [`${prefix}-50.dat`, `${prefix}-50.doc`, `${prefix}-50.docx`, `${prefix}-90.pdf`, `${prefix}-90.png`, `${prefix}-90.psd`]; + const futureFilenames = ['dee.dat', 'dee.doc', 'dee.docx', 'pee.pdf', 'pee.png', 'pee.psd']; const sourceFolder = './plugins/rename/test/fixtures/renameable'; const module = require('../lib/rename'); diff --git a/plugins/rename/test/rename.js b/plugins/rename/test/rename.js index 140b6915a..244d9c64f 100644 --- a/plugins/rename/test/rename.js +++ b/plugins/rename/test/rename.js @@ -1,70 +1,234 @@ 'use strict'; const test = require('tape'); +/* +* ####### # +* # # # # ##### # # #### #### #### #### # ## ##### ###### ##### +* # # ## # # # # # # # # # # # # # # # # # # +* ##### # # # # # # # # #### #### # # # # # # # ##### # # +* # # # # # # # ####### # # # # # # ###### # # # # +* # # # ## # # # # # # # # # # # # # # # # # # # +* # # # # ##### # # #### #### #### #### # # # # ###### ##### +* +*/ +test('Find many associated relative filenames', (assert) => { + const sourceFolder = './plugins/rename/test/fixtures/renameable/'; + const file = 'bee'; + const associatedFilenames = [`${file}.bat`, `${file}.bin`, `${file}.bmp`]; + const module = require('../lib/rename'); + + module.findAssociated(sourceFolder, associatedFilenames[0]) + .then((filenames) => { + if (filenames.length === 0) { + assert.fail(`No filenames found`); + assert.end(); + } + assert.plan(filenames.length); + filenames.forEach((filename, index) => { + const associatedFilename = associatedFilenames[index]; + assert.ok(filename.indexOf(associatedFilename.substr(1)) !== -1, + `Found associated filenames with path ${associatedFilename}`); + }); + }) + .catch((error) => assert.fail(`Associated files is not found (${error})`)); +}); + +test('Find many associated absolute filenames', (assert) => { + const sourceFolder = require('app-root-path').resolve('./test/fixtures/renameable/'); + const file = 'bee'; + const associatedFilenames = [`${file}.bat`, `${file}.bin`, `${file}.bmp`]; + const module = require('../lib/rename'); + + module.findAssociated(sourceFolder, associatedFilenames[0]) + .then((filenames) => { + if (filenames.length === 0) { + assert.fail(`No filenames found`); + assert.end(); + } + assert.plan(filenames.length); + filenames.forEach((filename, index) => { + const associatedFilename = associatedFilenames[index]; + assert.ok(filename.indexOf(associatedFilename.substr(1)) !== -1, + `Found associated filenames with path ${associatedFilename}`); + }); + }) + .catch((error) => assert.fail(`Associated files is not found (${error})`)); +}); + +test('Find no associated filenames', (assert) => { + const sourceFolder = './plugins/rename/test/fixtures/renameable/'; + const filename = 'FAKE'; + const associatedFilenames = []; + const module = require('../lib/rename'); + + assert.plan(1); + module.findAssociated(sourceFolder, filename) + .then((files) => assert.deepEqual(files, associatedFilenames, `Correctly found no files from fake path`)) + .catch((error) => assert.fail(`Associated files is not found (${error})`)); +}); + +/* +*###### # +*# # ###### ## #### #### # #### # # # # #### #### #### #### # ## ##### ###### ##### +*# # # # # # # # # # ## # # # # # # # # # # # # # # # # +*###### ##### # # #### #### # # # # # # # #### #### # # # # # # # ##### # # +*# # # ###### # # # # ### # # # ####### # # # # # # ###### # # # # +*# # # # # # # # # # # # # ## # # # # # # # # # # # # # # # # # +*# # ###### # # #### #### # #### # # # # #### #### #### #### # # # # ###### ##### +* +*/ +test('Reassign many associated absolute filenames', (assert) => { + const filepath = require('app-root-path').resolve('./plugins/rename/test/fixtures/renameable/'); + const absoluteAssociatedFilenames = [`${filepath}bee.bat`, `${filepath}bee.bin`, `${filepath}bee.bmp`]; + const futureFile = 'future'; + const futureAssociatedFilenames = [ + `${filepath}${futureFile}.bat`, + `${filepath}${futureFile}.bin`, + `${filepath}${futureFile}.bmp`, + ]; + const module = require('../lib/rename'); + + assert.plan(1); + module.reassignAssociated(absoluteAssociatedFilenames, futureFile) + .then((futureFilenames) => { + assert.deepEqual(futureAssociatedFilenames, futureFilenames, 'Reassigned filenames match'); + }); +}); + +/* +* ###### ###### +* # # ###### # # ## # # ###### # # ## ##### # # #### +* # # # ## # # # ## ## # # # # # # # # # +* ###### ##### # # # # # # ## # ##### ###### # # # ###### #### +* # # # # # # ###### # # # # ###### # # # # +* # # # # ## # # # # # # # # # # # # # +* # # ###### # # # # # # ###### # # # # # # #### +* +*/ test('Rename real source folder', (assert) => { - const filenames = ['cee.css', 'jay.js', 'tee.txt']; + const filenames = ['cee.css', 'jay.js', 'el.log']; const futureFilenames = ['changed.css', 'renamed.js', 'temp.txt']; const sourceFolder = './plugins/rename/test/fixtures/renameable'; const module = require('../lib/rename'); + assert.plan(1); module.renamePaths(sourceFolder, filenames, futureFilenames) - .then((success) => { - assert.equal(success, true, 'No errors'); - assert.end(); - }) - .catch((error) => { - assert.fail(`Rename failed ${error}`); - assert.end(); - }); + .then(success => assert.equal(success, true, 'No errors')) + .catch(error => assert.fail(`Rename failed ${error}`)); }); test('Restore real source folder', (assert) => { const filenames = ['changed.css', 'renamed.js', 'temp.txt']; - const futureFilenames = ['cee.css', 'jay.js', 'tee.txt']; + const futureFilenames = ['cee.css', 'jay.js', 'el.log']; const sourceFolder = './plugins/rename/test/fixtures/renameable'; const module = require('../lib/rename'); + assert.plan(1); module.renamePaths(sourceFolder, filenames, futureFilenames) - .then((success) => { - assert.equal(success, true, 'No errors'); - assert.end(); - }) - .catch((error) => { - assert.fail(`Rename failed ${error}`); - assert.end(); - }); + .then(success => assert.equal(success, true, 'No errors')) + .catch(error => assert.fail(`Rename failed ${error}`)); }); test('Caught fake source folder', (assert) => { - const filenames = ['cee.css', 'jay.js', 'tee.txt']; + const filenames = ['cee.css', 'jay.js', 'el.log']; const futureFilenames = ['changed.css', 'renamed.js', 'temp.txt']; const sourceFolder = './plugins/rename/test/fixtures/FAKE'; const module = require('../lib/rename'); + assert.plan(1); module.renamePaths(sourceFolder, filenames, futureFilenames) - .then(() => { - assert.fail('Code incorrectly found a fake folder'); - assert.end(); - }) - .catch(() => { - assert.pass('Fake folder not found'); - assert.end(); - }); + .then(() => assert.fail('Code incorrectly found a fake folder')) + .catch(() => assert.pass('Fake folder not found')); }); -test('Caught fake filenames', (assert) => { - const filenames = ['FAKEcee.css', 'FAKEjay.js', 'FAKEtee.txt']; +test('Caught fake source filenames', (assert) => { + const filenames = ['FAKEcee.css', 'FAKEjay.js', 'FAKEel.log']; const futureFilenames = ['changed.css', 'renamed.js', 'temp.txt']; const sourceFolder = './plugins/rename/test/fixtures/renameable'; const module = require('../lib/rename'); + assert.plan(1); module.renamePaths(sourceFolder, filenames, futureFilenames) - .then(() => { - assert.fail('Code incorrectly found a fake filename'); - assert.end(); + .then(() => assert.fail('Code incorrectly found a fake filename')) + .catch(() => assert.pass('Fake filename not found')); +}); + +test('Rename associated is false so one filename', (assert) => { + const filenames = ['bee.bat']; + const futureFilenames = ['rename_grouped.bat']; + const sourceFolder = './plugins/rename/test/fixtures/renameable'; + const module = require('../lib/rename'); + + module.renamePaths(sourceFolder, filenames, futureFilenames, { renameAssociated: false }) + .then(success => { + assert.plan(3); + assert.equal(success, true, 'No errors'); + const exist = require('../../exists/lib'); + exist.pathExists(`${sourceFolder}/bee.bin`) + .then(() => assert.pass('Associated bee.bin file remains untouched')) + .catch(error => assert.fail(`Bee.bin file does not exist ${error}`)); + exist.pathExists(`${sourceFolder}/bee.bmp`) + .then(() => assert.pass('Associated bee.bmp file remains untouched')) + .catch(error => assert.fail(`Bee.bmp file does not exist ${error}`)); + }) + .catch(error => assert.fail(`Rename failed ${error}`)); +}); + +test('Restore associated is false so one filename', (assert) => { + const filenames = ['rename_grouped.bat']; + const futureFilenames = ['bee.bat']; + const sourceFolder = './plugins/rename/test/fixtures/renameable'; + const module = require('../lib/rename'); + + assert.plan(1); + module.renamePaths(sourceFolder, filenames, futureFilenames, { renameAssociated: false }) + .then(success => assert.equal(success, true, 'No errors')) + .catch(error => assert.fail(`Rename failed ${error}`)); +}); + +test('Rename associated is true so six filenames', (assert) => { + const filenames = ['bee.bat', 'tee.txt']; + const futureFilenames = ['rename_grouped.bat', 'rename_associated.txt']; + const sourceFolder = './plugins/rename/test/fixtures/renameable'; + const module = require('../lib/rename'); + + module.renamePaths(sourceFolder, filenames, futureFilenames, { renameAssociated: true }) + .then((success) => { + assert.plan(7); + assert.equal(success, true, 'No errors'); + const exist = require('../../exists/lib'); + exist.pathExists(`${sourceFolder}/rename_grouped.bat`) + .then(() => assert.pass('Associated rename_grouped.bat file renamed with associated')) + .catch(error => assert.fail(`Rename_grouped.bin file does not exist ${error}`)); + exist.pathExists(`${sourceFolder}/rename_grouped.bin`) + .then(() => assert.pass('Associated rename_grouped.bin file renamed with associated')) + .catch(error => assert.fail(`Rename_grouped.bin file does not exist ${error}`)); + exist.pathExists(`${sourceFolder}/rename_grouped.bmp`) + .then(() => assert.pass('Associated rename_grouped.bmp file remains with associated')) + .catch(error => assert.fail(`Rename_grouped.bmp file does not exist ${error}`)); + exist.pathExists(`${sourceFolder}/rename_associated.txt`) + .then(() => assert.pass('Associated rename_associated.txt file renamed with associated')) + .catch(error => assert.fail(`Rename_associated.tar file does not exist ${error}`)); + exist.pathExists(`${sourceFolder}/rename_associated.tar`) + .then(() => assert.pass('Associated rename_associated.tar file renamed with associated')) + .catch(error => assert.fail(`Rename_associated.tar file does not exist ${error}`)); + exist.pathExists(`${sourceFolder}/rename_associated.tar`) + .then(() => assert.pass('Associated rename_associated.tar file remains with associated')) + .catch(error => assert.fail(`Rename_associated.tar file does not exist ${error}`)); }) - .catch(() => { - assert.pass('Fake filename not found'); - assert.end(); + .catch((error) => { + assert.fail(`Rename failed (${error})`); }); }); + +test('Restore associated is true so six filenames', (assert) => { + const filenames = ['rename_grouped.bat', 'rename_associated.txt']; + const futureFilenames = ['bee.bat', 'tee.txt']; + const sourceFolder = './plugins/rename/test/fixtures/renameable'; + const module = require('../lib/rename'); + + assert.plan(1); + module.renamePaths(sourceFolder, filenames, futureFilenames, { renameAssociated: true }) + .then((success) => assert.equal(success, true, 'No errors')) + .catch((error) => assert.fail(`Rename failed ${error}`)); +}); diff --git a/src/js/directory_contents.browser.js b/src/js/directory_contents.browser.js index bab0b9238..e17bd74b5 100644 --- a/src/js/directory_contents.browser.js +++ b/src/js/directory_contents.browser.js @@ -104,7 +104,8 @@ data: { filenames: JSON.stringify(getSortedAssets()), prefix: formattedDate, - source_folder: "." + qs.folder + source_folder: "." + qs.folder, + rename_associated: true }, success: function (response) { var $spinner = $("#spinner"), diff --git a/src/js/server.js b/src/js/server.js index e913ab9b5..95f2ee7ac 100644 --- a/src/js/server.js +++ b/src/js/server.js @@ -2,50 +2,51 @@ 'use strict'; const hapi = require('hapi'), - server = new hapi.Server(), - pkg = require('../../package'); + server = new hapi.Server(), + pkg = require('../../package'); server.connection({ "port": 8000 }); server.register([ - { register: require('inert') }, - { register: require('vision') }, - { register: require('./route.js') }, - { - register: require('../../plugins/rename/lib'), - routes: { prefix: '/admin' } - }, - { - register: require('hapi-swagger'), - options: { info: { title: 'history API', version: pkg.version } } - } + { register: require('inert') }, + { register: require('vision') }, + { register: require('./route.js') }, + { + register: require('../../plugins/rename/lib'), + routes: { prefix: '/admin' } + }, + { + register: require('hapi-swagger'), + options: { info: { title: 'history API', version: pkg.version } } + }, + { register: require('lout') } ], function (error) { - const notifier = require('node-notifier'), - hoek = require('hoek'); + const notifier = require('node-notifier'), + hoek = require('hoek'); - hoek.assert(!error, error); - var dust = require('dustjs-linkedin'), - dustViews = require("fs").readFileSync("./public/views.min.js"); - - require("tuxharness"); - dust.loadSource(dustViews); - console.log('Views loaded to cache'); + hoek.assert(!error, error); + var dust = require('dustjs-linkedin'), + dustViews = require("fs").readFileSync("./public/views.min.js"); - server.start(); - console.log('Server running at ' + server.info.uri); - notifier.notify({ - title: 'Server event', - message: 'Running at ' + server.info.uri + require("tuxharness"); + dust.loadSource(dustViews); + console.log('Views loaded to cache'); + + server.start(); + console.log('Server running at ' + server.info.uri); + notifier.notify({ + title: 'Server event', + message: 'Running at ' + server.info.uri }); }); server.views({ - "defaultExtension": "dust", - "engines": { - "dust": require('hapi-dust') - }, - "isCached": true, - "path": '../views', - "partialsPath": '../views', - "relativeTo": __dirname -}); \ No newline at end of file + "defaultExtension": "dust", + "engines": { + "dust": require('hapi-dust') + }, + "isCached": true, + "path": '../views', + "partialsPath": '../views', + "relativeTo": __dirname +});