From ccb6f1c5019b326771fb5b766c12a14b056a505b Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Fri, 13 May 2016 13:13:22 +0200 Subject: [PATCH 1/7] [IMP] document: indexation of MS documents Commit 3ced0ff61 removed the support of Microsoft documents for indexation. It makes sense for the old formats such as '.doc' since it requires an external tool ('antiword'), which could lead to a security issue. However, the new formats such '.docx' are simple xml files, therefore they could be indexed with the usual XML parsing tools. opw-677235 --- addons/document/models/ir_attachment.py | 106 +++++++++++++++++++----- 1 file changed, 86 insertions(+), 20 deletions(-) diff --git a/addons/document/models/ir_attachment.py b/addons/document/models/ir_attachment.py index c10f5b1013e..efa244f0dfa 100644 --- a/addons/document/models/ir_attachment.py +++ b/addons/document/models/ir_attachment.py @@ -7,34 +7,105 @@ from StringIO import StringIO import pyPdf -import openerp -from openerp.osv import fields, osv +from openerp.osv import osv _logger = logging.getLogger(__name__) +FTYPES = ['docx', 'pptx', 'xlsx', 'opendoc', 'pdf'] + +# Keep function in case it is necessary to do toUnicode(buf.encode('ascii', 'replace')) +def toUnicode(s): + try: + return s.decode('utf-8') + except UnicodeError: + try: + return s.decode('latin') + except UnicodeError: + try: + return s.encode('ascii') + except UnicodeError: + return s + +def textToString(element): + buff = u"" + for node in element.childNodes: + if node.nodeType == xml.dom.Node.TEXT_NODE: + buff += node.nodeValue + elif node.nodeType == xml.dom.Node.ELEMENT_NODE: + buff += textToString(node) + return buff + class IrAttachment(osv.osv): _inherit = 'ir.attachment' - def _index_odt(self, bin_data): + def _index_docx(self, bin_data): + '''Index Microsoft .docx documents''' buf = u"" f = StringIO(bin_data) if zipfile.is_zipfile(f): try: zf = zipfile.ZipFile(f) - self.content = xml.dom.minidom.parseString(zf.read("content.xml")) + content = xml.dom.minidom.parseString(zf.read("word/document.xml")) + for val in ["w:p", "w:h", "text:list"]: + for element in content.getElementsByTagName(val): + buf += textToString(element) + "\n" + except Exception: + pass + return buf + + def _index_pptx(self, bin_data): + '''Index Microsoft .pptx documents''' + + buf = u"" + f = StringIO(bin_data) + if zipfile.is_zipfile(f): + try: + zf = zipfile.ZipFile(f) + zf_filelist = [x for x in zf.namelist() if x.startswith('ppt/slides/slide')] + for i in range(1, len(zf_filelist) + 1): + content = xml.dom.minidom.parseString(zf.read('ppt/slides/slide%s.xml' % i)) + for val in ["a:t"]: + for element in content.getElementsByTagName(val): + buf += textToString(element) + "\n" + except Exception: + pass + return buf + + def _index_xlsx(self, bin_data): + '''Index Microsoft .xlsx documents''' + + buf = u"" + f = StringIO(bin_data) + if zipfile.is_zipfile(f): + try: + zf = zipfile.ZipFile(f) + content = xml.dom.minidom.parseString(zf.read("xl/sharedStrings.xml")) + for val in ["t"]: + for element in content.getElementsByTagName(val): + buf += textToString(element) + "\n" + except Exception: + pass + return buf + + def _index_opendoc(self, bin_data): + '''Index OpenDocument documents (.odt, .ods...)''' + + buf = u"" + f = StringIO(bin_data) + if zipfile.is_zipfile(f): + try: + zf = zipfile.ZipFile(f) + content = xml.dom.minidom.parseString(zf.read("content.xml")) for val in ["text:p", "text:h", "text:list"]: - for element in self.content.getElementsByTagName(val) : - for node in element.childNodes : - if node.nodeType == xml.dom.Node.TEXT_NODE : - buf += node.nodeValue - elif node.nodeType == xml.dom.Node.ELEMENT_NODE : - buf += self.textToString(node) - buf += "\n" + for element in content.getElementsByTagName(val): + buf += textToString(element) + "\n" except Exception: pass return buf def _index_pdf(self, bin_data): + '''Index PDF documents''' + buf = u"" if bin_data.startswith('%PDF-'): f = StringIO(bin_data) @@ -47,14 +118,9 @@ class IrAttachment(osv.osv): return buf def _index(self, cr, uid, bin_data, datas_fname, mimetype): - # try to index odt content - buf = self._index_odt(bin_data) - if buf: - return buf - # try to index pdf content - buf = self._index_pdf(bin_data) - if buf: - return buf + for ftype in FTYPES: + buf = getattr(self, '_index_%s' % ftype)(bin_data) + if buf: + return buf return super(IrAttachment, self)._index(cr, uid, bin_data, datas_fname, mimetype) - From aee53a3695940bf84dfb9572ef9f6b470c9a37c4 Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Fri, 13 May 2016 15:27:18 +0200 Subject: [PATCH 2/7] [FIX] setup: missing dep for RHEL-based distros --- setup.cfg | 1 + setup/package.dfcentos | 1 + 2 files changed, 2 insertions(+) diff --git a/setup.cfg b/setup.cfg index cccec6c615c..cc4ff5c2171 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,6 +27,7 @@ requires = python-requests python-vobject python-werkzeug + python-xlwt python-yaml pytz diff --git a/setup/package.dfcentos b/setup/package.dfcentos index d0f95a349ff..fc9cd3fa4cb 100644 --- a/setup/package.dfcentos +++ b/setup/package.dfcentos @@ -31,6 +31,7 @@ RUN yum install -d 0 -e 0 epel-release -y && \ python-requests \ python-vobject \ python-werkzeug \ + python-xlwt \ python-yaml \ pytz \ postgresql \ From 068acf76daef7e7145520b0bb1f7103656fa7885 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Fri, 13 May 2016 15:33:36 +0200 Subject: [PATCH 3/7] [FIX] web_kanban: quick redrag of kanban records When dropping a record, it is updated and rerendered. The problem with this behaviour is that if the record is redrag immediately after drop, jquery-ui throws an error as the widget the user is trying to re-move is being rerendered. The solution provided by this commit is to block the draggable feature while the record is being rerendered. --- addons/web_kanban/static/src/js/kanban_column.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/web_kanban/static/src/js/kanban_column.js b/addons/web_kanban/static/src/js/kanban_column.js index 7718991b10f..0094ad01743 100644 --- a/addons/web_kanban/static/src/js/kanban_column.js +++ b/addons/web_kanban/static/src/js/kanban_column.js @@ -91,7 +91,7 @@ var KanbanColumn = Widget.extend({ connectWith: '.o_kanban_group', revert: 0, delay: 0, - items: '> .o_kanban_record', + items: '> .o_kanban_record:not(.o_updating)', helper: 'clone', cursor: 'move', over: function () { @@ -117,6 +117,7 @@ var KanbanColumn = Widget.extend({ // adding record to this column self.records.push(record); record.setParent(self); + ui.item.addClass('o_updating'); self.trigger_up('kanban_column_add_record', {record: record}); } self.update_column(); From 98bd6d4f4a500fb82b989ba78c5059296b9cd92d Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Fri, 13 May 2016 16:19:32 +0200 Subject: [PATCH 4/7] [FIX] setup: use hard tabs GTFO --- setup/package.dfcentos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/package.dfcentos b/setup/package.dfcentos index fc9cd3fa4cb..853d9b77853 100644 --- a/setup/package.dfcentos +++ b/setup/package.dfcentos @@ -31,7 +31,7 @@ RUN yum install -d 0 -e 0 epel-release -y && \ python-requests \ python-vobject \ python-werkzeug \ - python-xlwt \ + python-xlwt \ python-yaml \ pytz \ postgresql \ From 9530a9f4985953533f9ab24d4635532dac274f9b Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Fri, 13 May 2016 13:32:39 +0200 Subject: [PATCH 5/7] [IMP] website: share widget and multi language The lang of the content of the "Share" widget was the one used when inserting it in the view. Thus if someone see a page with it in another language the title and url for sharing is not translated. This commit use the current page language to set the widget data. opw-676062 --- .../static/src/js/website.snippets.animation.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/addons/website/static/src/js/website.snippets.animation.js b/addons/website/static/src/js/website.snippets.animation.js index fa61feb7ec9..6702448fd58 100644 --- a/addons/website/static/src/js/website.snippets.animation.js +++ b/addons/website/static/src/js/website.snippets.animation.js @@ -105,12 +105,19 @@ animation.registry.parallax = animation.Class.extend({ animation.registry.share = animation.Class.extend({ selector: ".oe_share", start: function () { + var url_regex = /(\?(?:|.*&)(?:u|url|body)=)(.*?)(&|#|$)/; + var title_regex = /(\?(?:|.*&)(?:title|text|subject)=)(.*?)(&|#|$)/; var url = encodeURIComponent(window.location.href); var title = encodeURIComponent($("title").text()); this.$("a").each(function () { var $a = $(this); - var url_regex = /\{url\}|%7Burl%7D/, title_regex = /\{title\}|%7Btitle%7D/; - $a.attr("href", $(this).attr("href").replace(url_regex, url).replace(title_regex, title)); + $a.attr("href", function(i, href) { + return href.replace(url_regex, function (match, a, b, c) { + return a + url + c; + }).replace(title_regex, function (match, a, b, c) { + return a + title + c; + }); + }); if ($a.attr("target") && $a.attr("target").match(/_blank/i) && !$a.closest('.o_editable').length) { $a.on('click', function () { window.open(this.href,'','menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=550,width=600'); From 9b2d1533027dc25a9fd83c2a70af155d66018103 Mon Sep 17 00:00:00 2001 From: Damien Bouvy Date: Fri, 13 May 2016 17:08:28 +0200 Subject: [PATCH 6/7] [FIX] setup: atom doesn't want to use hard tabs even when told to This is now the 2d stupidest commit I ever did --- setup/package.dfcentos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/package.dfcentos b/setup/package.dfcentos index 853d9b77853..4b2a90647ef 100644 --- a/setup/package.dfcentos +++ b/setup/package.dfcentos @@ -31,7 +31,7 @@ RUN yum install -d 0 -e 0 epel-release -y && \ python-requests \ python-vobject \ python-werkzeug \ - python-xlwt \ + python-xlwt \ python-yaml \ pytz \ postgresql \ From 820f7e11c1e63e605c644cb80ba56c5425c2e87a Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 13 May 2016 17:32:00 +0200 Subject: [PATCH 7/7] [FIX] core: correct `fields.modified_draft` for triggers on other models --- openerp/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/fields.py b/openerp/fields.py index ea9afbbc7be..724cecbdb08 100644 --- a/openerp/fields.py +++ b/openerp/fields.py @@ -1020,7 +1020,7 @@ class Field(object): target = records - computed elif path and env.in_onchange: target = (target.browse(env.cache[field]) - computed).filtered( - lambda rec: rec._mapped_cache(path) & records + lambda rec: rec if path == 'id' else rec._mapped_cache(path) & records ) else: target = target.browse(env.cache[field]) - computed