Merge pull request #1860 from sebgie/issue#1854

This commit is contained in:
Hannah Wolfe 2014-01-06 23:13:48 +00:00
commit 80eac65e9b
7 changed files with 70 additions and 58 deletions

View File

@ -8,6 +8,59 @@
"click .js-delete": "handleDeleteClick"
},
initialize: function () {
// Disable import button and initizalize BlueImp file upload
$('#startupload').prop('disabled', true);
$('#importfile').fileupload({
url: Ghost.paths.apiRoot + '/db/',
limitMultiFileUploads: 1,
replaceFileInput: false,
headers: {
'X-CSRF-Token': $("meta[name='csrf-param']").attr('content')
},
dataType: 'json',
add: function (e, data) {
/*jslint unparam:true*/
data.context = $('#startupload').prop('disabled', false)
.click(function () {
$('#startupload').prop('disabled', true);
data.context = $('#startupload').text('Importing');
data.submit();
// unregister click event to allow different subsequent uploads
$('#startupload').off('click');
});
},
done: function (e, data) {
/*jslint unparam:true*/
$('#startupload').text('Import');
if (!data.result) {
throw new Error('No response received from server.');
}
if (!data.result.message) {
throw new Error('Unknown error');
}
Ghost.notifications.addItem({
type: 'success',
message: data.result.message,
status: 'passive'
});
},
error: function (response) {
$('#startupload').text('Import');
var responseJSON = response.responseJSON,
message = responseJSON && responseJSON.error ? responseJSON.error : 'unknown';
Ghost.notifications.addItem({
type: 'error',
message: ['A problem was encountered while importing new content to your blog. Error: ', message].join(''),
status: 'passive'
});
}
});
},
handleMenuClick: function (ev) {
ev.preventDefault();
@ -21,6 +74,7 @@
return false;
},
handleDeleteClick: function (ev) {
ev.preventDefault();
this.addSubview(new Ghost.Views.Modal({

View File

@ -16,7 +16,7 @@ api.notifications = require('./notifications');
api.settings = require('./settings');
db = {
'export': function (req, res) {
'exportContent': function (req, res) {
/*jslint unparam:true*/
return dataExport().then(function (exportedData) {
// Save the exported data to the file system for download
@ -44,11 +44,10 @@ db = {
});
});
},
'import': function (req, res) {
var notification,
databaseVersion;
'importContent': function (options) {
var databaseVersion;
if (!req.files.importfile || !req.files.importfile.path || req.files.importfile.name.indexOf('json') === -1) {
if (!options.importfile || !options.importfile.path || options.importfile.name.indexOf('json') === -1) {
/**
* Notify of an error if it occurs
*
@ -57,30 +56,17 @@ db = {
* - If there is no path
* - If the name doesn't have json in it
*/
return api.notifications.browse().then(function (notifications) {
notification = {
type: 'error',
message: "Must select a .json file to import",
status: 'persistent',
id: 'per-' + (notifications.length + 1)
};
return api.notifications.add(notification).then(function () {
res.redirect(configPaths().debugPath);
});
});
return when.reject({errorCode: 500, message: 'Please select a .json file to import.'});
}
api.settings.read({ key: 'databaseVersion' }).then(function (setting) {
return api.settings.read({ key: 'databaseVersion' }).then(function (setting) {
return when(setting.value);
}, function () {
return when('001');
}).then(function (version) {
databaseVersion = version;
// Read the file contents
return nodefn.call(fs.readFile, req.files.importfile.path);
return nodefn.call(fs.readFile, options.importfile.path);
}).then(function (fileContents) {
var importData,
error = '',
@ -132,32 +118,9 @@ db = {
}).then(function importSuccess() {
return api.settings.updateSettingsCache();
}).then(function () {
return api.notifications.browse();
}).then(function (notifications) {
notification = {
type: 'success',
message: "Posts, tags and other data successfully imported",
status: 'persistent',
id: 'per-' + (notifications.length + 1)
};
return api.notifications.add(notification).then(function () {
res.redirect(configPaths().debugPath);
});
return when.resolve({message: 'Posts, tags and other data successfully imported'});
}).otherwise(function importFailure(error) {
return api.notifications.browse().then(function (notifications) {
// Notify of an error if it occurs
notification = {
type: 'error',
message: error.message || error,
status: 'persistent',
id: 'per-' + (notifications.length + 1)
};
return api.notifications.add(notification).then(function () {
res.redirect(configPaths().debugPath);
});
});
return when.reject({errorCode: 500, message: error.message || error});
});
},
'deleteAllContent': function () {

View File

@ -45,7 +45,7 @@ function cacheInvalidationHeader(req, result) {
// takes the API method and wraps it so that it gets data from the request and returns a sensible JSON response
requestHandler = function (apiMethod) {
return function (req, res) {
var options = _.extend(req.body, req.query, req.params),
var options = _.extend(req.body, req.files, req.query, req.params),
apiContext = {
user: req.session && req.session.user
};

View File

@ -233,9 +233,6 @@ module.exports = function (server, dbHash) {
expressServer.use(express.json());
expressServer.use(express.urlencoded());
expressServer.use(subdir + '/ghost/upload/', middleware.busboy);
expressServer.use(subdir + '/ghost/api/v0.1/db/', middleware.busboy);
// ### Sessions
cookie = {
path: subdir + '/ghost',

View File

@ -43,8 +43,7 @@ module.exports = function (server) {
server.get('/ghost/settings*', middleware.auth, admin.settings);
server.get('/ghost/debug/', middleware.auth, admin.debug.index);
// We don't want to register bodyParser globally b/c of security concerns, so use multipart only here
server.post('/ghost/upload/', middleware.auth, admin.uploader);
server.post('/ghost/upload/', middleware.auth, middleware.busboy, admin.uploader);
// redirect to /ghost and let that do the authentication to prevent redirects to /ghost//admin etc.
server.get(/\/((ghost-admin|admin|wp-admin|dashboard|signin)\/?)$/, function (req, res) {

View File

@ -24,7 +24,7 @@ module.exports = function (server) {
server.del('/ghost/api/v0.1/notifications/:id', middleware.authAPI, api.requestHandler(api.notifications.destroy));
server.post('/ghost/api/v0.1/notifications/', middleware.authAPI, api.requestHandler(api.notifications.add));
// #### Import/Export
server.get('/ghost/api/v0.1/db/', middleware.auth, api.db['export']);
server.post('/ghost/api/v0.1/db/', middleware.auth, api.db['import']);
server.get('/ghost/api/v0.1/db/', middleware.auth, api.db.exportContent);
server.post('/ghost/api/v0.1/db/', middleware.authAPI, middleware.busboy, api.requestHandler(api.db.importContent));
server.del('/ghost/api/v0.1/db/', middleware.authAPI, api.requestHandler(api.db.deleteAllContent));
};

View File

@ -25,13 +25,12 @@
</div>
</fieldset>
</form>
<form id="settings-import" method="post" action="{{adminUrl}}/api/v0.1/db/" enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="{{csrfToken}}" />
<form id="settings-import" enctype="multipart/form-data">
<fieldset>
<div class="form-group">
<label>Import</label>
<input type="file" class="button-add" name="importfile" />
<input type="submit" class="button-save" value="Import" />
<input type="file" class="button-add" name="importfile" id="importfile" />
<button type="submit" class="button-save" value="Import" id="startupload" >Import</button>
<p>Import from another Ghost installation. If you import a user, this will replace the current user & log you out.</p>
</div>
</fieldset>