diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index a4000856afe..646e80f432e 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -17,4 +17,5 @@ This module provides the core of the OpenERP Web Client. 'qweb' : [ "static/src/xml/*.xml", ], + 'bootstrap': True, # load translations for login screen } diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 59e69c36b16..da7c0b0e4f2 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1124,7 +1124,7 @@ class Binary(http.Controller): if filename_field: fields.append(filename_field) if data: - res = { field: data } + res = {field: data, filename_field: jdata.get('filename', None)} elif id: res = Model.read([int(id)], fields, context)[0] else: diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index a41986b4193..da6605a08e9 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -5639,14 +5639,17 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance. } else { instance.web.blockUI(); var c = instance.webclient.crashmanager; + var filename_fieldname = this.node.attrs.filename; + var filename_field = this.view.fields && this.view.fields[filename_fieldname]; this.session.get_file({ url: '/web/binary/saveas_ajax', data: {data: JSON.stringify({ model: this.view.dataset.model, id: (this.view.datarecord.id || ''), field: this.name, - filename_field: (this.node.attrs.filename || ''), + filename_field: (filename_fieldname || ''), data: instance.web.form.is_bin_size(value) ? null : value, + filename: filename_field ? filename_field.get('value') : null, context: this.view.dataset.get_context() })}, complete: instance.web.unblockUI, diff --git a/openerp/addons/base/ir/ir_mail_server.py b/openerp/addons/base/ir/ir_mail_server.py index 638eb385fad..d16d652bdab 100644 --- a/openerp/addons/base/ir/ir_mail_server.py +++ b/openerp/addons/base/ir/ir_mail_server.py @@ -363,6 +363,27 @@ class ir_mail_server(osv.osv): msg.attach(part) return msg + def _get_default_bounce_address(self, cr, uid, context=None): + '''Compute the default bounce address. + + The default bounce address is used to set the envelop address if no + envelop address is provided in the message. It is formed by properly + joining the parameters "mail.catchall.alias" and + "mail.catchall.domain". + + If "mail.catchall.alias" is not set it defaults to "postmaster-odoo". + + If "mail.catchall.domain" is not set, return None. + + ''' + get_param = self.pool['ir.config_parameter'].get_param + postmaster = get_param(cr, uid, 'mail.bounce.alias', + default='postmaster-odoo', + context=context,) + domain = get_param(cr, uid, 'mail.catchall.domain', context=context) + if postmaster and domain: + return '%s@%s' % (postmaster, domain) + def send_email(self, cr, uid, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, context=None): @@ -378,8 +399,9 @@ class ir_mail_server(osv.osv): and fails if not found. :param message: the email.message.Message to send. The envelope sender will be extracted from the - ``Return-Path`` or ``From`` headers. The envelope recipients will be - extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. + ``Return-Path`` (if present), or will be set to the default bounce address. + The envelope recipients will be extracted from the combined list of ``To``, + ``CC`` and ``BCC`` headers. :param mail_server_id: optional id of ir.mail_server to use for sending. overrides other smtp_* arguments. :param smtp_server: optional hostname of SMTP server to use :param smtp_encryption: optional TLS mode, one of 'none', 'starttls' or 'ssl' (see ir.mail_server fields for explanation) @@ -390,7 +412,14 @@ class ir_mail_server(osv.osv): :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ - smtp_from = message['Return-Path'] or message['From'] + # Use the default bounce address **only if** no Return-Path was + # provided by caller. Caller may be using Variable Envelope Return + # Path (VERP) to detect no-longer valid email addresses. + smtp_from = message['Return-Path'] + if not smtp_from: + smtp_from = self._get_default_bounce_address(cr, uid, context=context) + if not smtp_from: + smtp_from = message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. diff --git a/openerp/tools/safe_eval.py b/openerp/tools/safe_eval.py index 808cabc8d5f..e6e63076fe7 100644 --- a/openerp/tools/safe_eval.py +++ b/openerp/tools/safe_eval.py @@ -32,6 +32,7 @@ condition/math builtins. # - safe_eval in tryton http://hg.tryton.org/hgwebdir.cgi/trytond/rev/bbb5f73319ad from opcode import HAVE_ARGUMENT, opmap, opname +from psycopg2 import OperationalError from types import CodeType import logging @@ -321,6 +322,10 @@ def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=Fal raise except openerp.exceptions.AccessError: raise + except OperationalError: + # Do not hide PostgreSQL low-level exceptions, to let the auto-replay + # of serialized transactions work its magic + raise except Exception, e: import sys exc_info = sys.exc_info()