From 4232a081640134eaced9c89834a5e15ee1c7362b Mon Sep 17 00:00:00 2001 From: "Adrien Peiffer (ACSONE)" Date: Thu, 26 Jan 2017 10:29:04 +0100 Subject: [PATCH 1/5] [FIX] mass_mailing: ondelete cascade on transient The test wizard will be dropped eventually but it is not possible to delete the mass-mailing before the transient is cleaned too due to the required field. To make it faster, add a ondelete cascade on the field. Closes #15217 --- addons/mass_mailing/wizard/test_mailing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/mass_mailing/wizard/test_mailing.py b/addons/mass_mailing/wizard/test_mailing.py index 20c57f80609..ea570ebb755 100644 --- a/addons/mass_mailing/wizard/test_mailing.py +++ b/addons/mass_mailing/wizard/test_mailing.py @@ -11,7 +11,8 @@ class TestMassMailing(osv.TransientModel): _columns = { 'email_to': fields.char('Recipients', required=True, help='Comma-separated list of email addresses.'), - 'mass_mailing_id': fields.many2one('mail.mass_mailing', 'Mailing', required=True), + 'mass_mailing_id': fields.many2one( + 'mail.mass_mailing', 'Mailing', required=True, ondelete='cascade'), } _defaults = { From cfcc37bca50baf43843ac938ea26cf23d7a30b25 Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Thu, 26 Jan 2017 08:34:41 +0100 Subject: [PATCH 2/5] [FIX] expression: leaf in o2m with m2o inherits'd field The reverse field of a one2many could be originating from an inherits'd field, this was solved in some instance with f5e5bbda. The issue could still happen in some instances when doing a comparison of: - the one2many field to a False value, - the one2many with a negative operator and an empty set to negate, With this change, the ORM is used in such a situation. closes #15234 opw-704962 --- openerp/addons/test_inherit/tests/test_inherit.py | 6 ++++++ openerp/osv/expression.py | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/openerp/addons/test_inherit/tests/test_inherit.py b/openerp/addons/test_inherit/tests/test_inherit.py index f6057817ee4..8e12b0b7e08 100644 --- a/openerp/addons/test_inherit/tests/test_inherit.py +++ b/openerp/addons/test_inherit/tests/test_inherit.py @@ -74,6 +74,12 @@ class test_inherits(common.TransactionCase): self.assertIn(daughter, partner_demo.daughter_ids) # search the partner from the daughter record + partners = self.env['res.partner'].search([('daughter_ids', 'like', 'not existing daugther')]) + self.assertFalse(partners) + partners = self.env['res.partner'].search([('daughter_ids', 'not like', 'not existing daugther')]) + self.assertIn(partner_demo, partners) + partners = self.env['res.partner'].search([('daughter_ids', '!=', False)]) + self.assertIn(partner_demo, partners) partners = self.env['res.partner'].search([('daughter_ids', 'in', daughter.ids)]) self.assertIn(partner_demo, partners) diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py index f29fc8f7084..2be571e538c 100644 --- a/openerp/osv/expression.py +++ b/openerp/osv/expression.py @@ -981,7 +981,14 @@ class expression(object): if call_null: o2m_op = 'in' if operator in NEGATIVE_TERM_OPERATORS else 'not in' - push(create_substitution_leaf(leaf, ('id', o2m_op, select_distinct_from_where_not_null(cr, column._fields_id, comodel._table)), model)) + # determine ids from column._fields_id + if comodel._fields[column._fields_id].store: + ids1 = select_distinct_from_where_not_null(cr, column._fields_id, comodel._table) + else: + ids2 = comodel.search(cr, uid, [(column._fields_id, '!=', False)], context=context) + recs = comodel.browse(cr, SUPERUSER_ID, ids2, {'prefetch_fields': False}) + ids1 = recs.mapped(column._fields_id).ids + push(create_substitution_leaf(leaf, ('id', o2m_op, ids1), model)) elif column._type == 'many2many': rel_table, rel_id1, rel_id2 = column._sql_names(model) From 15583a48134db69ebd9d93f955c3b4d6692e4b99 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 27 Jan 2017 02:29:11 +0100 Subject: [PATCH 3/5] [FIX] module: allow disabling 1-click install As discussed on issue #15225, it should be possible for system administrators to disable the 1-click installation system. The plan is to disable the feature by default, but make it relatively easy to turn on when it is explicitly desired. 1. At the moment we cannot guarantee that all Apps published on the Odoo Apps Store are safe. And it is a security risk to let end-users deploy Python code on their Odoo servers without requiring any review/deployment by a competent system administrator. We will work on improving the validation process of the Store, but this will require time, and won't probably be a 100% safe process in any case. 2. The one-click install feature is however really useful to help non-technical users install Apps, as long as the feature has been explicitly allowed by the system administrator. This is a common feature in other software suites as well. So we'd like to keep it as an opt-in feature. 3. Administrators of multi-tenant servers, cloud hosting services, etc. understandably expect to be able to turn off the feature for security/control reasons. 4. By turning off the feature by default, but still exposing it in the UI, we keep it *discoverable* for users. The error message should be helpful to direct users to their sysadmins. 5. By using the permissions of the download folder as a flag for turning off the feature, we avoid introducing an extra server parameter. The folder is still created (read-only) by default, for the sole purpose of making it easier to locate. Fixes #15225 --- openerp/addons/base/module/module.py | 9 +++++++++ openerp/modules/module.py | 2 +- openerp/tools/config.py | 9 +++++---- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index 1105ccd0fa1..158edf311d8 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -659,6 +659,15 @@ class module(osv.osv): if not self.pool['res.users'].has_group(cr, uid, 'base.group_system'): raise openerp.exceptions.AccessDenied() + # One-click install is opt-in - cfr Issue #15225 + ad_dir = openerp.tools.config.addons_data_dir + if not os.access(ad_dir, os.W_OK): + msg = (_("Automatic install of downloaded Apps is currently disabled.") + "\n\n" + + _("To enable it, make sure this directory exists and is writable on the server:") + + "\n%s" % ad_dir) + _logger.warning(msg) + raise openerp.exceptions.AccessError(msg) + apps_server = urlparse.urlparse(self.get_apps_server(cr, uid, context=context)) OPENERP = openerp.release.product_name.lower() diff --git a/openerp/modules/module.py b/openerp/modules/module.py index e9e643001f0..7c1f8b104a8 100644 --- a/openerp/modules/module.py +++ b/openerp/modules/module.py @@ -94,7 +94,7 @@ def initialize_sys_path(): global hooked dd = tools.config.addons_data_dir - if dd not in ad_paths: + if os.access(dd, os.R_OK) and dd not in ad_paths: ad_paths.append(dd) for ad in tools.config['addons_path'].split(','): diff --git a/openerp/tools/config.py b/openerp/tools/config.py index f1dd6251036..8e30845063f 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -686,10 +686,11 @@ class configmanager(object): def addons_data_dir(self): d = os.path.join(self['data_dir'], 'addons', release.series) if not os.path.exists(d): - os.makedirs(d, 0700) - else: - assert os.access(d, os.W_OK), \ - "%s: directory is not writable" % d + try: + # try to make +rx placeholder dir, will need manual +w to activate it + os.makedirs(d, 0500) + except OSError: + logging.getLogger(__name__).debug('Failed to create addons data dir %s', d) return d @property From af381bf7ecc68d983da0896ec114ab14c686f855 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 27 Jan 2017 14:40:34 +0100 Subject: [PATCH 4/5] [I18N] base: update PO template for 15583a4 --- openerp/addons/base/i18n/base.pot | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/i18n/base.pot b/openerp/addons/base/i18n/base.pot index c1fd7cc0ad6..d6c4e8f070d 100644 --- a/openerp/addons/base/i18n/base.pot +++ b/openerp/addons/base/i18n/base.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 8.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-10-19 06:31+0000\n" -"PO-Revision-Date: 2015-10-19 06:31+0000\n" +"POT-Creation-Date: 2017-01-27 13:39+0000\n" +"PO-Revision-Date: 2017-01-27 13:39+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -4941,6 +4941,12 @@ msgstr "" msgid "Automatic Installation" msgstr "" +#. module: base +#: code:addons/base/module/module.py:693 +#, python-format +msgid "Automatic install of downloaded Apps is currently disabled." +msgstr "" + #. module: base #: help:ir.translation,state:0 msgid "Automatically set to let administators find new terms that might need to be translated" @@ -14355,6 +14361,12 @@ msgstr "" msgid "To be upgraded" msgstr "" +#. module: base +#: code:addons/base/module/module.py:666 +#, python-format +msgid "To enable it, make sure this directory exists and is writable on the server:" +msgstr "" + #. module: base #: view:ir.actions.todo:base.ir_actions_todo_tree msgid "Todo" From f431cee99a8a63d693a228309033edcadb256539 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 23 Nov 2016 16:14:24 +0100 Subject: [PATCH 5/5] [FIX] hw_escpos: increase timeout for slow matrix printers Some printers (e.g. matrix/impact printers) may have a hard time keeping up with the text output, and may trigger timeout errors because of this, even though they would otherwise produce a correct result. Increasing the default timeout to 5s (from the default 1s) should take care of most slow printers out there. --- addons/hw_escpos/escpos/printer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hw_escpos/escpos/printer.py b/addons/hw_escpos/escpos/printer.py index d52668b50f9..238a69e5fc8 100644 --- a/addons/hw_escpos/escpos/printer.py +++ b/addons/hw_escpos/escpos/printer.py @@ -82,7 +82,7 @@ class Usb(Escpos): def _raw(self, msg): """ Print any command sent in raw format """ - if len(msg) != self.device.write(self.out_ep, msg, self.interface): + if len(msg) != self.device.write(self.out_ep, msg, self.interface, timeout=5000): self.device.write(self.out_ep, self.errorText, self.interface) raise TicketNotPrinted()