FIX: don't break the message bus when restoring a backup

This commit is contained in:
Régis Hanol 2015-08-27 20:02:13 +02:00
parent 2589a75c46
commit 96c23d51a2
8 changed files with 78 additions and 109 deletions

View File

@ -1,90 +0,0 @@
/**
Data model for representing a backup
@class Backup
@extends Discourse.Model
@namespace Discourse
@module Discourse
**/
Discourse.Backup = Discourse.Model.extend({
/**
Destroys the current backup
@method destroy
@returns {Promise} a promise that resolves when the backup has been destroyed
**/
destroy: function() {
return Discourse.ajax("/admin/backups/" + this.get("filename"), { type: "DELETE" });
},
/**
Starts the restoration of the current backup
@method restore
@returns {Promise} a promise that resolves when the backup has started being restored
**/
restore: function() {
return Discourse.ajax("/admin/backups/" + this.get("filename") + "/restore", { type: "POST" });
}
});
Discourse.Backup.reopenClass({
/**
Finds a list of backups
@method find
@returns {Promise} a promise that resolves to the array of {Discourse.Backup} backup
**/
find: function() {
return PreloadStore.getAndRemove("backups", function() {
return Discourse.ajax("/admin/backups.json");
}).then(function(backups) {
return backups.map(function (backup) { return Discourse.Backup.create(backup); });
});
},
/**
Starts a backup
@method start
@returns {Promise} a promise that resolves when the backup has started
**/
start: function (withUploads) {
if (withUploads === undefined) { withUploads = true; }
return Discourse.ajax("/admin/backups", { type: "POST", data: { with_uploads: withUploads } }).then(function(result) {
if (!result.success) { bootbox.alert(result.message); }
});
},
/**
Cancels a backup
@method cancel
@returns {Promise} a promise that resolves when the backup has been cancelled
**/
cancel: function() {
return Discourse.ajax("/admin/backups/cancel.json").then(function(result) {
if (!result.success) { bootbox.alert(result.message); }
});
},
/**
Rollbacks the database to the previous working state
@method rollback
@returns {Promise} a promise that resolves when the rollback is done
**/
rollback: function() {
return Discourse.ajax("/admin/backups/rollback.json").then(function(result) {
if (!result.success) {
bootbox.alert(result.message);
} else {
// redirect to homepage (session might be lost)
window.location.pathname = Discourse.getURL("/");
}
});
}
});

View File

@ -0,0 +1,56 @@
const Backup = Discourse.Model.extend({
destroy() {
return Discourse.ajax("/admin/backups/" + this.get("filename"), { type: "DELETE" });
},
restore() {
return Discourse.ajax("/admin/backups/" + this.get("filename") + "/restore", {
type: "POST",
data: { client_id: window.MessageBus.clientId }
});
}
});
Backup.reopenClass({
find() {
return PreloadStore.getAndRemove("backups", () => Discourse.ajax("/admin/backups.json"))
.then(backups => backups.map(backup => Backup.create(backup)));
},
start(withUploads) {
if (withUploads === undefined) { withUploads = true; }
return Discourse.ajax("/admin/backups", {
type: "POST",
data: {
with_uploads: withUploads,
client_id: window.MessageBus.clientId
}
}).then(result => {
if (!result.success) { bootbox.alert(result.message); }
});
},
cancel() {
return Discourse.ajax("/admin/backups/cancel.json")
.then(result => {
if (!result.success) { bootbox.alert(result.message); }
});
},
rollback() {
return Discourse.ajax("/admin/backups/rollback.json")
.then(result => {
if (!result.success) {
bootbox.alert(result.message);
} else {
// redirect to homepage (session might be lost)
window.location.pathname = Discourse.getURL("/");
}
});
}
});
export default Backup;

View File

@ -9,9 +9,7 @@ function inject() {
name = arguments[1],
singletonName = Ember.String.underscore(name).replace(/_/, '-') + ':main';
Array.prototype.slice.call(arguments, 2).forEach(function(dest) {
app.inject(dest, name, singletonName);
});
Array.prototype.slice.call(arguments, 2).forEach(dest => app.inject(dest, name, singletonName));
}
function injectAll(app, name) {
@ -20,6 +18,7 @@ function injectAll(app, name) {
export default {
name: "inject-discourse-objects",
initialize(container, app) {
const appEvents = AppEvents.create();
app.register('app-events:main', appEvents, { instantiate: false });
@ -29,16 +28,13 @@ export default {
app.register('store:main', Store);
inject(app, 'store', 'route', 'controller');
// Inject Discourse.Site to avoid using Discourse.Site.current()
const site = Discourse.Site.current();
app.register('site:main', site, { instantiate: false });
injectAll(app, 'site');
// Inject Discourse.SiteSettings to avoid using Discourse.SiteSettings globals
app.register('site-settings:main', Discourse.SiteSettings, { instantiate: false });
injectAll(app, 'siteSettings');
// Inject Session for transient data
app.register('session:main', Session.current(), { instantiate: false });
injectAll(app, 'session');
@ -46,7 +42,7 @@ export default {
inject(app, 'currentUser', 'component', 'route', 'controller');
app.register('message-bus:main', window.MessageBus, { instantiate: false });
inject(app, 'messageBus', 'route', 'controller', 'view', 'component');
injectAll(app, 'messageBus');
app.register('location:discourse-location', DiscourseLocation);
}

View File

@ -25,7 +25,8 @@ class Admin::BackupsController < Admin::AdminController
def create
opts = {
publish_to_message_bus: true,
with_uploads: params.fetch(:with_uploads) == "true"
with_uploads: params.fetch(:with_uploads) == "true",
client_id: params[:client_id],
}
BackupRestore.backup!(current_user.id, opts)
rescue BackupRestore::OperationRunningError
@ -70,8 +71,12 @@ class Admin::BackupsController < Admin::AdminController
end
def restore
filename = params.fetch(:id)
BackupRestore.restore!(current_user.id, filename, true)
opts = {
filename: params.fetch(:id),
client_id: params.fetch(:client_id),
publish_to_message_bus: true,
}
BackupRestore.restore!(current_user.id, opts)
rescue BackupRestore::OperationRunningError
render json: failed_json.merge(message: I18n.t("backup.operation_already_running"))
else

View File

@ -13,8 +13,8 @@ module BackupRestore
start! BackupRestore::Backuper.new(user_id, opts)
end
def self.restore!(user_id, filename, publish_to_message_bus=false)
start! BackupRestore::Restorer.new(user_id, filename, publish_to_message_bus)
def self.restore!(user_id, opts={})
start! BackupRestore::Restorer.new(user_id, opts)
end
def self.rollback!

View File

@ -6,6 +6,7 @@ module BackupRestore
def initialize(user_id, opts={})
@user_id = user_id
@client_id = opts[:client_id]
@publish_to_message_bus = opts[:publish_to_message_bus] || false
@with_uploads = opts[:with_uploads].nil? ? true : opts[:with_uploads]
@ -336,7 +337,7 @@ module BackupRestore
def publish_log(message, timestamp)
return unless @publish_to_message_bus
data = { timestamp: timestamp, operation: "backup", message: message }
MessageBus.publish(BackupRestore::LOGS_CHANNEL, data, user_ids: [@user_id])
MessageBus.publish(BackupRestore::LOGS_CHANNEL, data, user_ids: [@user_id], client_ids: [@client_id])
end
def save_log(message, timestamp)

View File

@ -7,8 +7,11 @@ module BackupRestore
attr_reader :success
def initialize(user_id, filename, publish_to_message_bus = false)
@user_id, @filename, @publish_to_message_bus = user_id, filename, publish_to_message_bus
def initialize(user_id, opts={})
@user_id = user_id
@client_id = opts[:client_id]
@filename = opts[:filename]
@publish_to_message_bus = opts[:publish_to_message_bus] || false
ensure_restore_is_enabled
ensure_no_operation_is_running
@ -45,8 +48,6 @@ module BackupRestore
switch_schema!
# TOFIX: MessageBus is busted...
migrate_database
reconnect_database
reload_site_settings
@ -354,7 +355,7 @@ module BackupRestore
def publish_log(message, timestamp)
return unless @publish_to_message_bus
data = { timestamp: timestamp, operation: "restore", message: message }
MessageBus.publish(BackupRestore::LOGS_CHANNEL, data, user_ids: [@user_id])
MessageBus.publish(BackupRestore::LOGS_CHANNEL, data, user_ids: [@user_id], client_ids: [@client_id])
end
def save_log(message, timestamp)

View File

@ -63,7 +63,7 @@ class DiscourseCLI < Thor
begin
puts "Starting restore: #{filename}"
restorer = BackupRestore::Restorer.new(Discourse.system_user.id, filename)
restorer = BackupRestore::Restorer.new(Discourse.system_user.id, filename: filename)
restorer.run
puts 'Restore done.'
rescue BackupRestore::FilenameMissingError