[FIX] fully reimplement dumping a DB so that it works correctly

* handler should be an httprequest, as we're returning a binary file (maybe we could use ajax with file API abd b64, but... not now)
* use cookie-hack to know when the file is downloading (or is finished downloading, not sure which, not that it matters) so we can add some kind of UI signal

bzr revid: xmo@openerp.com-20110801131254-ik4m8yyc526pz7rf
This commit is contained in:
Xavier Morel 2011-08-01 15:12:54 +02:00
parent 56ebc5946c
commit 0fd884d234
3 changed files with 50 additions and 29 deletions

View File

@ -191,18 +191,16 @@ class Database(openerpweb.Controller):
return {'error': e.faultCode, 'title': 'Drop Database'}
return {'error': 'Could not drop database !', 'title': 'Drop Database'}
@openerpweb.jsonrequest
def backup_db(self, req, fields):
password, db = operator.itemgetter(
'backup_pwd', 'backup_db')(
dict(map(operator.itemgetter('name', 'value'), fields)))
@openerpweb.httprequest
def backup_db(self, req, backup_db, backup_pwd, token):
try:
res = req.session.proxy("db").dump(password, db)
if res:
cherrypy.response.headers['Content-Type'] = "application/data"
cherrypy.response.headers['Content-Disposition'] = 'filename="' + db + '.dump"'
return base64.decodestring(res)
db_dump = base64.decodestring(
req.session.proxy("db").dump(backup_pwd, backup_db))
cherrypy.response.headers['Content-Type'] = "application/octet-stream; charset=binary"
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="' + backup_db + '.dump"'
cherrypy.response.cookie['fileToken'] = token
cherrypy.response.cookie['fileToken']['path'] = '/'
return db_dump
except xmlrpclib.Fault, e:
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
return {'error': e.faultCode, 'title': 'Backup Database'}

View File

@ -787,30 +787,51 @@ openerp.base.Database = openerp.base.Controller.extend({
}
});
},
wait_for_file: function (token, cleanup) {
var cookie_name = 'fileToken',
cookie_length = cookie_name.length;
var timer = setInterval(function () {
var cookies = document.cookie.split(';');
for(var i=0; i<cookies.length; ++i) {
var cookie = cookies[i].replace(/^\s*/, '');
if(!cookie.indexOf(cookie_name) === 0) { continue; }
var cookie_val = cookie.substring(cookie_length + 1);
if(parseInt(cookie_val, 10) !== token) { continue; }
// clear waiter
clearInterval(timer);
// clear cookie
document.cookie = _.sprintf("%s=;expires=%s;path=/",
cookie_name, new Date().toGMTString());
if (cleanup) { cleanup(); }
}
}, 100);
},
do_db_backup: function() {
var self = this;
self.$option_id.html(QWeb.render("BackupDB", self));
self.$option_id.find("form[name=backup_db_form]").validate({
submitHandler: function (form) {
var fields = $(form).serializeArray();
// need to detect when the file is done downloading (not used
// yet, but we'll need it to fix the UI e.g. with a throbber
// while dump is being generated), iframe load event only fires
// when the iframe content loads, so we need to go smarter:
// http://geekswithblogs.net/GruffCode/archive/2010/10/28/detecting-the-file-download-dialog-in-the-browser.aspx
var $target = $('#backup-target'),
token = new Date().getTime();
if (!$target.length) {
$target = $('<iframe id="backup-target" style="display: none;">')
.appendTo(document.body);
}
$(form).find('input[name=token]').val(token);
form.submit();
self.rpc("/base/database/backup_db", {'fields': fields}, function(result) {
if (!result.error) {
self.notification.notify("Backup Database", "Backup has been created for the database");
} else {
$('<div>').dialog({
modal: true,
title: result.title,
buttons: {
Ok: function() {
$(this).dialog("close");
}
}
}).html(result.error);
}
});
// TODO: implement cleanup function when request-in-flight UI added
var cleanup = null;
self.wait_for_file(token, cleanup);
}
});
},

View File

@ -149,7 +149,9 @@
</form>
</t>
<t t-name="BackupDB">
<form name="backup_db_form" method="POST">
<form name="backup_db_form" method="POST" target="backup-target"
action="/base/database/backup_db">
<input type="hidden" name="token"/>
<table width="100%">
<tr>
<td class="option_string">