Skip to content

Commit 80eac65

Browse files
committed
Merge pull request #1860 from sebgie/issue#1854
2 parents f17b320 + 6220bd1 commit 80eac65

File tree

7 files changed

+70
-58
lines changed

7 files changed

+70
-58
lines changed

core/client/views/debug.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,59 @@
88
"click .js-delete": "handleDeleteClick"
99
},
1010

11+
initialize: function () {
12+
// Disable import button and initizalize BlueImp file upload
13+
$('#startupload').prop('disabled', true);
14+
$('#importfile').fileupload({
15+
url: Ghost.paths.apiRoot + '/db/',
16+
limitMultiFileUploads: 1,
17+
replaceFileInput: false,
18+
headers: {
19+
'X-CSRF-Token': $("meta[name='csrf-param']").attr('content')
20+
},
21+
dataType: 'json',
22+
add: function (e, data) {
23+
/*jslint unparam:true*/
24+
data.context = $('#startupload').prop('disabled', false)
25+
.click(function () {
26+
$('#startupload').prop('disabled', true);
27+
data.context = $('#startupload').text('Importing');
28+
data.submit();
29+
// unregister click event to allow different subsequent uploads
30+
$('#startupload').off('click');
31+
});
32+
},
33+
done: function (e, data) {
34+
/*jslint unparam:true*/
35+
$('#startupload').text('Import');
36+
if (!data.result) {
37+
throw new Error('No response received from server.');
38+
}
39+
if (!data.result.message) {
40+
throw new Error('Unknown error');
41+
}
42+
43+
Ghost.notifications.addItem({
44+
type: 'success',
45+
message: data.result.message,
46+
status: 'passive'
47+
});
48+
},
49+
error: function (response) {
50+
$('#startupload').text('Import');
51+
var responseJSON = response.responseJSON,
52+
message = responseJSON && responseJSON.error ? responseJSON.error : 'unknown';
53+
Ghost.notifications.addItem({
54+
type: 'error',
55+
message: ['A problem was encountered while importing new content to your blog. Error: ', message].join(''),
56+
status: 'passive'
57+
});
58+
}
59+
60+
});
61+
62+
},
63+
1164
handleMenuClick: function (ev) {
1265
ev.preventDefault();
1366

@@ -21,6 +74,7 @@
2174

2275
return false;
2376
},
77+
2478
handleDeleteClick: function (ev) {
2579
ev.preventDefault();
2680
this.addSubview(new Ghost.Views.Modal({

core/server/api/db.js

Lines changed: 9 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ api.notifications = require('./notifications');
1616
api.settings = require('./settings');
1717

1818
db = {
19-
'export': function (req, res) {
19+
'exportContent': function (req, res) {
2020
/*jslint unparam:true*/
2121
return dataExport().then(function (exportedData) {
2222
// Save the exported data to the file system for download
@@ -44,11 +44,10 @@ db = {
4444
});
4545
});
4646
},
47-
'import': function (req, res) {
48-
var notification,
49-
databaseVersion;
47+
'importContent': function (options) {
48+
var databaseVersion;
5049

51-
if (!req.files.importfile || !req.files.importfile.path || req.files.importfile.name.indexOf('json') === -1) {
50+
if (!options.importfile || !options.importfile.path || options.importfile.name.indexOf('json') === -1) {
5251
/**
5352
* Notify of an error if it occurs
5453
*
@@ -57,30 +56,17 @@ db = {
5756
* - If there is no path
5857
* - If the name doesn't have json in it
5958
*/
60-
return api.notifications.browse().then(function (notifications) {
61-
notification = {
62-
type: 'error',
63-
message: "Must select a .json file to import",
64-
status: 'persistent',
65-
id: 'per-' + (notifications.length + 1)
66-
};
67-
68-
69-
70-
return api.notifications.add(notification).then(function () {
71-
res.redirect(configPaths().debugPath);
72-
});
73-
});
59+
return when.reject({errorCode: 500, message: 'Please select a .json file to import.'});
7460
}
7561

76-
api.settings.read({ key: 'databaseVersion' }).then(function (setting) {
62+
return api.settings.read({ key: 'databaseVersion' }).then(function (setting) {
7763
return when(setting.value);
7864
}, function () {
7965
return when('001');
8066
}).then(function (version) {
8167
databaseVersion = version;
8268
// Read the file contents
83-
return nodefn.call(fs.readFile, req.files.importfile.path);
69+
return nodefn.call(fs.readFile, options.importfile.path);
8470
}).then(function (fileContents) {
8571
var importData,
8672
error = '',
@@ -132,32 +118,9 @@ db = {
132118
}).then(function importSuccess() {
133119
return api.settings.updateSettingsCache();
134120
}).then(function () {
135-
return api.notifications.browse();
136-
}).then(function (notifications) {
137-
notification = {
138-
type: 'success',
139-
message: "Posts, tags and other data successfully imported",
140-
status: 'persistent',
141-
id: 'per-' + (notifications.length + 1)
142-
};
143-
144-
return api.notifications.add(notification).then(function () {
145-
res.redirect(configPaths().debugPath);
146-
});
121+
return when.resolve({message: 'Posts, tags and other data successfully imported'});
147122
}).otherwise(function importFailure(error) {
148-
return api.notifications.browse().then(function (notifications) {
149-
// Notify of an error if it occurs
150-
notification = {
151-
type: 'error',
152-
message: error.message || error,
153-
status: 'persistent',
154-
id: 'per-' + (notifications.length + 1)
155-
};
156-
157-
return api.notifications.add(notification).then(function () {
158-
res.redirect(configPaths().debugPath);
159-
});
160-
});
123+
return when.reject({errorCode: 500, message: error.message || error});
161124
});
162125
},
163126
'deleteAllContent': function () {

core/server/api/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ function cacheInvalidationHeader(req, result) {
4545
// takes the API method and wraps it so that it gets data from the request and returns a sensible JSON response
4646
requestHandler = function (apiMethod) {
4747
return function (req, res) {
48-
var options = _.extend(req.body, req.query, req.params),
48+
var options = _.extend(req.body, req.files, req.query, req.params),
4949
apiContext = {
5050
user: req.session && req.session.user
5151
};

core/server/middleware/index.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,6 @@ module.exports = function (server, dbHash) {
233233
expressServer.use(express.json());
234234
expressServer.use(express.urlencoded());
235235

236-
expressServer.use(subdir + '/ghost/upload/', middleware.busboy);
237-
expressServer.use(subdir + '/ghost/api/v0.1/db/', middleware.busboy);
238-
239236
// ### Sessions
240237
cookie = {
241238
path: subdir + '/ghost',

core/server/routes/admin.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ module.exports = function (server) {
4343
server.get('/ghost/settings*', middleware.auth, admin.settings);
4444
server.get('/ghost/debug/', middleware.auth, admin.debug.index);
4545

46-
// We don't want to register bodyParser globally b/c of security concerns, so use multipart only here
47-
server.post('/ghost/upload/', middleware.auth, admin.uploader);
46+
server.post('/ghost/upload/', middleware.auth, middleware.busboy, admin.uploader);
4847

4948
// redirect to /ghost and let that do the authentication to prevent redirects to /ghost//admin etc.
5049
server.get(/\/((ghost-admin|admin|wp-admin|dashboard|signin)\/?)$/, function (req, res) {

core/server/routes/api.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ module.exports = function (server) {
2424
server.del('/ghost/api/v0.1/notifications/:id', middleware.authAPI, api.requestHandler(api.notifications.destroy));
2525
server.post('/ghost/api/v0.1/notifications/', middleware.authAPI, api.requestHandler(api.notifications.add));
2626
// #### Import/Export
27-
server.get('/ghost/api/v0.1/db/', middleware.auth, api.db['export']);
28-
server.post('/ghost/api/v0.1/db/', middleware.auth, api.db['import']);
27+
server.get('/ghost/api/v0.1/db/', middleware.auth, api.db.exportContent);
28+
server.post('/ghost/api/v0.1/db/', middleware.authAPI, middleware.busboy, api.requestHandler(api.db.importContent));
2929
server.del('/ghost/api/v0.1/db/', middleware.authAPI, api.requestHandler(api.db.deleteAllContent));
3030
};

core/server/views/debug.hbs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,12 @@
2525
</div>
2626
</fieldset>
2727
</form>
28-
<form id="settings-import" method="post" action="{{adminUrl}}/api/v0.1/db/" enctype="multipart/form-data">
29-
<input type="hidden" name="_csrf" value="{{csrfToken}}" />
28+
<form id="settings-import" enctype="multipart/form-data">
3029
<fieldset>
3130
<div class="form-group">
3231
<label>Import</label>
33-
<input type="file" class="button-add" name="importfile" />
34-
<input type="submit" class="button-save" value="Import" />
32+
<input type="file" class="button-add" name="importfile" id="importfile" />
33+
<button type="submit" class="button-save" value="Import" id="startupload" >Import</button>
3534
<p>Import from another Ghost installation. If you import a user, this will replace the current user & log you out.</p>
3635
</div>
3736
</fieldset>

0 commit comments

Comments
 (0)