mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Moves storage module to use prototypes for inheritance and structure.
addresses #2852 - Moves storage modules to use prototypes and to create prototypes that inherit from the base storage ctor. - Makes storage/base conform to an all Promise interface.
This commit is contained in:
parent
bd163ada46
commit
66845def85
7 changed files with 109 additions and 105 deletions
|
@ -29,7 +29,7 @@ upload = {
|
||||||
* @returns {Promise} Success
|
* @returns {Promise} Success
|
||||||
*/
|
*/
|
||||||
add: function (options) {
|
add: function (options) {
|
||||||
var store = storage.get_storage(),
|
var store = storage.getStorage(),
|
||||||
type,
|
type,
|
||||||
ext,
|
ext,
|
||||||
filepath;
|
filepath;
|
||||||
|
|
|
@ -278,7 +278,7 @@ setupMiddleware = function (server) {
|
||||||
|
|
||||||
// Static assets
|
// Static assets
|
||||||
expressServer.use('/shared', express['static'](path.join(corePath, '/shared'), {maxAge: utils.ONE_HOUR_MS}));
|
expressServer.use('/shared', express['static'](path.join(corePath, '/shared'), {maxAge: utils.ONE_HOUR_MS}));
|
||||||
expressServer.use('/content/images', storage.get_storage().serve());
|
expressServer.use('/content/images', storage.getStorage().serve());
|
||||||
expressServer.use('/ghost/scripts', express['static'](path.join(corePath, '/built/scripts'), {maxAge: utils.ONE_YEAR_MS}));
|
expressServer.use('/ghost/scripts', express['static'](path.join(corePath, '/built/scripts'), {maxAge: utils.ONE_YEAR_MS}));
|
||||||
expressServer.use('/public', express['static'](path.join(corePath, '/built/public'), {maxAge: utils.ONE_YEAR_MS}));
|
expressServer.use('/public', express['static'](path.join(corePath, '/built/public'), {maxAge: utils.ONE_YEAR_MS}));
|
||||||
|
|
||||||
|
|
|
@ -1,52 +1,48 @@
|
||||||
var moment = require('moment'),
|
var moment = require('moment'),
|
||||||
path = require('path'),
|
path = require('path');
|
||||||
Promise = require('bluebird'),
|
|
||||||
baseStore;
|
|
||||||
|
|
||||||
// TODO: would probably be better to put these on the prototype and have proper constructors etc
|
function StorageBase() {
|
||||||
baseStore = {
|
}
|
||||||
'getTargetDir': function (baseDir) {
|
|
||||||
var m = moment(new Date().getTime()),
|
|
||||||
month = m.format('MMM'),
|
|
||||||
year = m.format('YYYY');
|
|
||||||
|
|
||||||
if (baseDir) {
|
StorageBase.prototype.getTargetDir = function (baseDir) {
|
||||||
return path.join(baseDir, year, month);
|
var m = moment(new Date().getTime()),
|
||||||
}
|
month = m.format('MMM'),
|
||||||
|
year = m.format('YYYY');
|
||||||
|
|
||||||
return path.join(year, month);
|
if (baseDir) {
|
||||||
},
|
return path.join(baseDir, year, month);
|
||||||
'generateUnique': function (store, dir, name, ext, i, done) {
|
|
||||||
var self = this,
|
|
||||||
filename,
|
|
||||||
append = '';
|
|
||||||
|
|
||||||
if (i) {
|
|
||||||
append = '-' + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
filename = path.join(dir, name + append + ext);
|
|
||||||
|
|
||||||
store.exists(filename).then(function (exists) {
|
|
||||||
if (exists) {
|
|
||||||
setImmediate(function () {
|
|
||||||
i = i + 1;
|
|
||||||
self.generateUnique(store, dir, name, ext, i, done);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
done(filename);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'getUniqueFileName': function (store, image, targetDir) {
|
|
||||||
var ext = path.extname(image.name),
|
|
||||||
name = path.basename(image.name, ext).replace(/[\W]/gi, '-'),
|
|
||||||
self = this;
|
|
||||||
|
|
||||||
return new Promise(function (resolve) {
|
|
||||||
self.generateUnique(store, targetDir, name, ext, 0, resolve);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return path.join(year, month);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = baseStore;
|
StorageBase.prototype.generateUnique = function (store, dir, name, ext, i) {
|
||||||
|
var self = this,
|
||||||
|
filename,
|
||||||
|
append = '';
|
||||||
|
|
||||||
|
if (i) {
|
||||||
|
append = '-' + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = path.join(dir, name + append + ext);
|
||||||
|
|
||||||
|
return store.exists(filename).then(function (exists) {
|
||||||
|
if (exists) {
|
||||||
|
i = i + 1;
|
||||||
|
return self.generateUnique(store, dir, name, ext, i);
|
||||||
|
} else {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
StorageBase.prototype.getUniqueFileName = function (store, image, targetDir) {
|
||||||
|
var ext = path.extname(image.name),
|
||||||
|
name = path.basename(image.name, ext).replace(/[\W]/gi, '-'),
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
return self.generateUnique(store, targetDir, name, ext, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = StorageBase;
|
||||||
|
|
|
@ -1,22 +1,26 @@
|
||||||
var errors = require('../errors'),
|
var errors = require('../errors'),
|
||||||
storage;
|
storage = {};
|
||||||
|
|
||||||
function get_storage() {
|
function getStorage(storageChoice) {
|
||||||
// TODO: this is where the check for storage apps should go
|
// TODO: this is where the check for storage apps should go
|
||||||
// Local file system is the default
|
// Local file system is the default. Fow now that is all we support.
|
||||||
var storageChoice = 'localfilesystem';
|
storageChoice = 'localfilesystem';
|
||||||
|
|
||||||
if (storage) {
|
if (storage[storageChoice]) {
|
||||||
return storage;
|
return storage[storageChoice];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: determine if storage has all the necessary methods
|
// TODO: determine if storage has all the necessary methods.
|
||||||
storage = require('./' + storageChoice);
|
storage[storageChoice] = require('./' + storageChoice);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
errors.logError(e);
|
errors.logError(e);
|
||||||
}
|
}
|
||||||
return storage;
|
|
||||||
|
// Instantiate and cache the storage module instance.
|
||||||
|
storage[storageChoice] = new storage[storageChoice]();
|
||||||
|
|
||||||
|
return storage[storageChoice];
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.get_storage = get_storage;
|
module.exports.getStorage = getStorage;
|
|
@ -1,56 +1,57 @@
|
||||||
// # Local File System Image Storage module
|
// # Local File System Image Storage module
|
||||||
// The (default) module for storing images, using the local file system
|
// The (default) module for storing images, using the local file system
|
||||||
|
|
||||||
var _ = require('lodash'),
|
var express = require('express'),
|
||||||
express = require('express'),
|
|
||||||
fs = require('fs-extra'),
|
fs = require('fs-extra'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
|
util = require('util'),
|
||||||
Promise = require('bluebird'),
|
Promise = require('bluebird'),
|
||||||
errors = require('../errors'),
|
errors = require('../errors'),
|
||||||
config = require('../config'),
|
config = require('../config'),
|
||||||
utils = require('../utils'),
|
utils = require('../utils'),
|
||||||
baseStore = require('./base'),
|
baseStore = require('./base');
|
||||||
|
|
||||||
localFileStore;
|
function LocalFileStore() {
|
||||||
|
}
|
||||||
|
util.inherits(LocalFileStore, baseStore);
|
||||||
|
|
||||||
localFileStore = _.extend(baseStore, {
|
// ### Save
|
||||||
// ### Save
|
// Saves the image to storage (the file system)
|
||||||
// Saves the image to storage (the file system)
|
// - image is the express image object
|
||||||
// - image is the express image object
|
// - returns a promise which ultimately returns the full url to the uploaded image
|
||||||
// - returns a promise which ultimately returns the full url to the uploaded image
|
LocalFileStore.prototype.save = function (image) {
|
||||||
'save': function (image) {
|
var targetDir = this.getTargetDir(config.paths.imagesPath),
|
||||||
var targetDir = this.getTargetDir(config.paths.imagesPath),
|
targetFilename;
|
||||||
targetFilename;
|
|
||||||
|
|
||||||
return this.getUniqueFileName(this, image, targetDir).then(function (filename) {
|
return this.getUniqueFileName(this, image, targetDir).then(function (filename) {
|
||||||
targetFilename = filename;
|
targetFilename = filename;
|
||||||
return Promise.promisify(fs.mkdirs)(targetDir);
|
return Promise.promisify(fs.mkdirs)(targetDir);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
return Promise.promisify(fs.copy)(image.path, targetFilename);
|
return Promise.promisify(fs.copy)(image.path, targetFilename);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
// The src for the image must be in URI format, not a file system path, which in Windows uses \
|
// The src for the image must be in URI format, not a file system path, which in Windows uses \
|
||||||
// For local file system storage can use relative path so add a slash
|
// For local file system storage can use relative path so add a slash
|
||||||
var fullUrl = (config.paths.subdir + '/' + config.paths.imagesRelPath + '/' + path.relative(config.paths.imagesPath, targetFilename)).replace(new RegExp('\\' + path.sep, 'g'), '/');
|
var fullUrl = (config.paths.subdir + '/' + config.paths.imagesRelPath + '/' +
|
||||||
return fullUrl;
|
path.relative(config.paths.imagesPath, targetFilename)).replace(new RegExp('\\' + path.sep, 'g'), '/');
|
||||||
}).catch(function (e) {
|
return fullUrl;
|
||||||
errors.logError(e);
|
}).catch(function (e) {
|
||||||
return Promise.reject(e);
|
errors.logError(e);
|
||||||
|
return Promise.reject(e);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalFileStore.prototype.exists = function (filename) {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
fs.exists(filename, function (exists) {
|
||||||
|
resolve(exists);
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
|
};
|
||||||
|
|
||||||
'exists': function (filename) {
|
// middleware for serving the files
|
||||||
return new Promise(function (resolve) {
|
LocalFileStore.prototype.serve = function () {
|
||||||
fs.exists(filename, function (exists) {
|
// For some reason send divides the max age number by 1000
|
||||||
resolve(exists);
|
return express['static'](config.paths.imagesPath, {maxAge: utils.ONE_YEAR_MS});
|
||||||
});
|
};
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// middleware for serving the files
|
module.exports = LocalFileStore;
|
||||||
'serve': function () {
|
|
||||||
// For some reason send divides the max age number by 1000
|
|
||||||
return express['static'](config.paths.imagesPath, {maxAge: utils.ONE_YEAR_MS});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = localFileStore;
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ describe('Upload API', function () {
|
||||||
// Doesn't test the DB
|
// Doesn't test the DB
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
storage.get_storage.restore();
|
storage.getStorage.restore();
|
||||||
fs.unlink.restore();
|
fs.unlink.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ describe('Upload API', function () {
|
||||||
store.save = sinon.stub().returns(Promise.resolve('URL'));
|
store.save = sinon.stub().returns(Promise.resolve('URL'));
|
||||||
store.exists = sinon.stub().returns(Promise.resolve(true));
|
store.exists = sinon.stub().returns(Promise.resolve(true));
|
||||||
store.destroy = sinon.stub().returns(Promise.resolve());
|
store.destroy = sinon.stub().returns(Promise.resolve());
|
||||||
sinon.stub(storage, 'get_storage').returns(store);
|
sinon.stub(storage, 'getStorage').returns(store);
|
||||||
sinon.stub(fs, 'unlink').yields();
|
sinon.stub(fs, 'unlink').yields();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ var fs = require('fs-extra'),
|
||||||
rewire = require('rewire'),
|
rewire = require('rewire'),
|
||||||
_ = require('lodash'),
|
_ = require('lodash'),
|
||||||
config = rewire('../../server/config'),
|
config = rewire('../../server/config'),
|
||||||
localfilesystem = rewire('../../server/storage/localfilesystem');
|
LocalFileStore = rewire('../../server/storage/localfilesystem'),
|
||||||
|
localfilesystem;
|
||||||
|
|
||||||
// To stop jshint complaining
|
// To stop jshint complaining
|
||||||
should.equal(true, true);
|
should.equal(true, true);
|
||||||
|
@ -16,10 +17,10 @@ describe('Local File System Storage', function () {
|
||||||
|
|
||||||
var image,
|
var image,
|
||||||
overrideConfig = function (newConfig) {
|
overrideConfig = function (newConfig) {
|
||||||
var existingConfig = localfilesystem.__get__('config'),
|
var existingConfig = LocalFileStore.__get__('config'),
|
||||||
updatedConfig = _.extend(existingConfig, newConfig);
|
updatedConfig = _.extend(existingConfig, newConfig);
|
||||||
config.set(updatedConfig);
|
config.set(updatedConfig);
|
||||||
localfilesystem.__set__('config', updatedConfig);
|
LocalFileStore.__set__('config', updatedConfig);
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
@ -38,6 +39,8 @@ describe('Local File System Storage', function () {
|
||||||
|
|
||||||
// Sat Sep 07 2013 21:24
|
// Sat Sep 07 2013 21:24
|
||||||
this.clock = sinon.useFakeTimers(new Date(2013, 8, 7, 21, 24).getTime());
|
this.clock = sinon.useFakeTimers(new Date(2013, 8, 7, 21, 24).getTime());
|
||||||
|
|
||||||
|
localfilesystem = new LocalFileStore();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
|
@ -181,4 +184,4 @@ describe('Local File System Storage', function () {
|
||||||
}).catch(done);
|
}).catch(done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
Loading…
Add table
Reference in a new issue