0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

Merge pull request #204 from jgable/exportUI

Import and Export UI
This commit is contained in:
Hannah Wolfe 2013-06-24 08:43:21 -07:00
commit 6632687104
9 changed files with 209 additions and 52 deletions

3
.gitignore vendored
View file

@ -31,4 +31,5 @@ projectFilesBackup
/core/admin/assets/sass/layouts/config.rb
/core/admin/assets/sass/modules/config.rb
/core/admin/assets/sass/modules/bourbon
/ghost/.idea/
/ghost/.idea/
/core/shared/data/export/exported*

7
app.js
View file

@ -39,7 +39,7 @@
ghost.app().use(express.errorHandler({ dumpExceptions: true, showStack: true }));
ghost.app().use(express.logger('dev'));
ghost.app().use(I18n.load(ghost));
ghost.app().use(express.bodyParser());
ghost.app().use(express.bodyParser({}));
ghost.app().use(express.cookieParser('try-ghost'));
ghost.app().use(express.cookieSession({ cookie: { maxAge: 60000000 }}));
ghost.app().use(ghost.initTheme(ghost.app()));
@ -146,8 +146,9 @@
ghost.app().get('/ghost/content', auth, admin.content);
ghost.app().get('/ghost/settings*', auth, admin.settings);
ghost.app().get('/ghost/debug', auth, admin.debug.index);
ghost.app().get('/ghost/debug/db/delete/', auth, admin.debug.dbdelete);
ghost.app().get('/ghost/debug/db/populate/', auth, admin.debug.dbpopulate);
ghost.app().get('/ghost/debug/db/export/', auth, admin.debug['export']);
ghost.app().post('/ghost/debug/db/import/', auth, admin.debug.import);
ghost.app().get('/ghost/debug/db/reset/', auth, admin.debug.reset);
ghost.app().get(/^\/(ghost$|(ghost-admin|admin|wp-admin|dashboard|login)\/?)/, auth, function (req, res) {
res.redirect('/ghost/');
});

View file

@ -11,7 +11,8 @@
'settings/' : 'settings',
'settings(/:pane)' : 'settings',
'editor/' : 'editor',
'editor(/:id)' : 'editor'
'editor(/:id)' : 'editor',
'debug/' : 'debug',
},
blog: function () {
@ -41,6 +42,10 @@
}
},
debug: function () {
Ghost.currentView = new Ghost.Views.Debug({ el: "#main" });
},
dashboard: function () {
var widgets = new Ghost.Collections.Widgets();

View file

@ -1,5 +1,5 @@
/*global window, document, Ghost, Backbone, $, _ */
(function () {
/*global window, document, Ghost, Backbone, $, JST, _ */
(function (_, undefined) {
"use strict";
Ghost.View = Backbone.View.extend({
@ -42,4 +42,34 @@
});
}());
Ghost.TemplateView = Ghost.View.extend({
templateName: "widget",
template: function (data) {
return JST[this.templateName](data);
},
templateData: function () {
if (this.model) {
return this.model.toJSON();
}
if (this.collection) {
return this.collection.toJSON();
}
return {};
},
render: function () {
this.$el.html(this.template(this.templateData()));
if (_.isFunction(this.afterRender)) {
this.afterRender();
}
return this;
}
});
}(_));

View file

@ -0,0 +1,25 @@
/*global jQuery, window, document, Ghost, Backbone, $, _, alert */
(function ($, _, Backbone, Ghost, undefined) {
"use strict";
Ghost.Views.Debug = Ghost.View.extend({
events: {
"click .settings-menu a": "handleMenuClick"
},
handleMenuClick: function (ev) {
ev.preventDefault();
var $target = $(ev.currentTarget);
// Hide the current content
this.$(".settings-content").hide();
// Show the clicked content
this.$("#debug-" + $target.attr("class")).show();
return false;
}
});
}(jQuery, _, Backbone, window.Ghost));

View file

@ -3,8 +3,13 @@
"use strict";
var Ghost = require('../../ghost'),
dataExport = require('../../shared/data/export'),
dataImport = require('../../shared/data/import'),
_ = require('underscore'),
fs = require('fs'),
path = require('path'),
when = require('when'),
nodefn = require('when/node/function'),
api = require('../../shared/api'),
ghost = new Ghost(),
@ -158,34 +163,108 @@
adminNav: setSelected(adminNavbar, 'settings')
});
},
'dbdelete': function (req, res) {
fs.writeFile(__dirname + '/../ghost/data/datastore.db', '', function (error) {
if (error) {
req.flash('error', error);
} else {
req.flash('success', 'Everything got deleted');
}
res.redirect('/ghost/debug');
});
'export': function (req, res) {
// Get current version from settings
api.settings.read({ key: "currentVersion" })
.then(function (setting) {
// Export the current versions data
return dataExport(setting.value);
}, function () {
// If no setting, assume 001
return dataExport("001");
})
.then(function (exportedData) {
// Save the exported data to the file system for download
var fileName = path.resolve(__dirname + '/../../shared/data/export/exported-' + (new Date().getTime()) + '.json');
return nodefn.call(fs.writeFile, fileName, JSON.stringify(exportedData)).then(function () {
return when(fileName);
});
})
.then(function (exportedFilePath) {
// Send the exported data file
res.download(exportedFilePath, 'GhostData.json');
})
.otherwise(function (error) {
// Notify of an error if it occurs
req.flash("error", error.message || error);
res.redirect("/ghost/debug");
});
},
'dbpopulate': function (req, res) {
dataProvider.populateData(function (error) {
if (error) {
req.flash('error', error);
} else {
req.flash('success', 'Data populated');
}
res.redirect('/ghost/debug');
});
'import': function (req, res) {
if (!req.files.importfile) {
// Notify of an error if it occurs
req.flash("error", "Must select a file to import");
return res.redirect("/ghost/debug");
}
// Get the current version for importing
api.settings.read({ key: "currentVersion" })
.then(function (setting) {
return when(setting.value);
}, function () {
return when("001");
})
.then(function (currentVersion) {
// Read the file contents
return nodefn.call(fs.readFile, req.files.importfile.path)
.then(function (fileContents) {
var importData;
// Parse the json data
try {
importData = JSON.parse(fileContents);
} catch (e) {
return when.reject(new Error("Failed to parse the import file"));
}
if (!importData.meta || !importData.meta.version) {
return when.reject(new Error("Import data does not specify version"));
}
// Import for the current version
return dataImport(currentVersion, importData);
});
})
.then(function () {
req.flash("success", "Data imported");
})
.otherwise(function (error) {
// Notify of an error if it occurs
req.flash("error", error.message || error);
})
.then(function () {
res.redirect("/ghost/debug");
});
},
'newUser': function (req, res) {
dataProvider.addNewUser(req, function (error) {
if (error) {
req.flash('error', error);
} else {
req.flash('success', 'User Added');
}
});
'reset': function (req, res) {
// Grab the current version so we can get the migration
api.settings.read({ key: "currentVersion" })
.then(function (setting) {
var migration = require("../../shared/data/migration/" + setting.value);
// Run the downward migration
return migration.down();
}, function () {
// If no version in the DB, assume 001
var migration = require("../../shared/data/migration/001");
// Run the downward migration
return migration.down();
})
.then(function () {
// Re-initalize the providers (should run the migration up again)
return dataProvider.init();
})
.then(function () {
req.flash("success", "Database reset");
})
.otherwise(function (error) {
req.flash("error", error.message || error);
})
.then(function () {
res.redirect('/ghost/debug');
});
}
}
};

View file

@ -1,37 +1,48 @@
{{!< default}}
<div class="wrapper">
<div id="debug-page" class="wrapper">
<aside class="settings-sidebar" role="complementary">
<header>
<h1 class="title">Ugly Debug Tools</h1>
</header>
<nav class="settings-menu">
<ul>
<li class="Data management"><a href="#">General</a></li>
<li><a class="general" href="javascript:void(0);">General</a></li>
</ul>
</nav>
</aside>
<section class="settings-content">
<section id="debug-general" class="settings-content" style="display: block">
<header>
<h2 class="title">General</h2>
<button class="button-save">Save</button>
</header>
<section class="content">
{{> flashes}}
<form id="settings-general">
<form id="settings-export">
<fieldset>
<label>
<b>Delete Database</b>
<a href="/ghost/debug/db/delete/" class="button-delete">Delete</a>
<p>Delete the entire database so you can start again with empty tables</p>
</label>
<label>
<b>Populate Database</b>
<a href="/ghost/debug/db/populate/" class="button-add">Populate</a>
<p>Populate the database with the default fixtures
(<strong>Warning: </strong>only works on empty DB)</p>
<b>Export</b>
<a href="/ghost/debug/db/export/" class="button-save">Export</a>
<p>Export the blog settings and data.</p>
</label>
</fieldset>
</form>
<form id="settings-import" method="post" action="/ghost/debug/db/import/" enctype="multipart/form-data">
<fieldset>
<label>
<b>Import</b>
<input type="file" class="button-add" name="importfile"></input>
<input type="submit" class="button-save" value="Import"></input>
<p>Import from another Ghost installation.</p>
</label>
</fieldset>
</form>
<form id="settings-resetdb">
<fieldset>
<label>
<b>Reset Database</b>
<a href="/ghost/debug/db/reset/" class="button-delete">Reset</a>
<p>Delete the entire database so you can start again with empty tables</p>
</label>
</fieldset>
</form>
</section>
</section>

View file

@ -64,6 +64,7 @@
<script src="/core/admin/assets/js/views/blog.js"></script>
<script src="/core/admin/assets/js/views/editor.js"></script>
<script src="/core/admin/assets/js/views/settings.js"></script>
<script src="/core/admin/assets/js/views/debug.js"></script>
<script src="/core/admin/assets/js/router.js"></script>
{{{block "bodyScripts"}}}
<script>

View file

@ -82,16 +82,20 @@
settings = {
browse: function browse(options) {
return dataProvider.Settings.browse(options).then(settingsObject);
return dataProvider.Settings.browse(options).then(settingsObject, errors.logAndThrowError);
},
read: function read(options) {
return dataProvider.Settings.read(options.key).then(function (setting) {
if (!setting) {
return when.reject("Unable to find setting: " + options.key);
}
return _.pick(setting.toJSON(), 'key', 'value');
});
}, errors.logAndThrowError);
},
edit: function edit(settings) {
settings = settingsCollection(settings);
return dataProvider.Settings.edit(settings).then(settingsObject);
return dataProvider.Settings.edit(settings).then(settingsObject, errors.logAndThrowError);
}
};