Files
odoo_source/addons/web_editor/models/ir_ui_view.py
T
Simon Lejeune 5c54571f4e [FIX] web_editor: remove the editable key if no write on the model
The `check_access_rule` call allow to remove the `editable` key from the
rendering context (which will lead to the display of the editor bar) if
an access rule prevents the edition of the ir.ui.view record. Also remove
it in case the user has no write access on the model (i.e. demo user).
2016-07-05 17:44:56 +02:00

128 lines
5.0 KiB
Python

# -*- coding: utf-8 -*-
import copy
import openerp
from openerp.exceptions import AccessError
from openerp.osv import osv
from lxml import etree, html
from openerp import api
class view(osv.osv):
_inherit = 'ir.ui.view'
@api.cr_uid_ids_context
def render(self, cr, uid, id_or_xml_id, values=None, engine='ir.qweb', context=None):
if isinstance(id_or_xml_id, list):
id_or_xml_id = id_or_xml_id[0]
if not values:
values = {}
if values.get('editable'):
try:
if not isinstance(id_or_xml_id, (int, long)):
if '.' not in id_or_xml_id:
raise ValueError('Invalid template id: %r' % (id_or_xml_id,))
id_or_xml_id = self.get_view_id(cr, uid, id_or_xml_id, context=context)
self.check_access_rights(cr, uid, 'write')
self.check_access_rule(cr, uid, [id_or_xml_id], 'write', context=context)
except AccessError:
values['editable'] = False
return super(view, self).render(cr, uid, id_or_xml_id, values=values, engine=engine, context=context)
#------------------------------------------------------
# Save from html
#------------------------------------------------------
def extract_embedded_fields(self, cr, uid, arch, context=None):
return arch.xpath('//*[@data-oe-model != "ir.ui.view"]')
@api.model
def save_embedded_field(self, el):
Model = self.env[el.get('data-oe-model')]
field = el.get('data-oe-field')
model = 'ir.qweb.field.' + el.get('data-oe-type')
converter = self.env[model] if model in self.env else self.env['ir.qweb.field']
value = converter.from_html(Model, Model._fields[field], el)
if value is not None:
# TODO: batch writes?
Model.browse(int(el.get('data-oe-id'))).write({field: value})
def _pretty_arch(self, arch):
# remove_blank_string does not seem to work on HTMLParser, and
# pretty-printing with lxml more or less requires stripping
# whitespace: http://lxml.de/FAQ.html#why-doesn-t-the-pretty-print-option-reformat-my-xml-output
# so serialize to XML, parse as XML (remove whitespace) then serialize
# as XML (pretty print)
arch_no_whitespace = etree.fromstring(
etree.tostring(arch, encoding='utf-8'),
parser=etree.XMLParser(encoding='utf-8', remove_blank_text=True))
return etree.tostring(
arch_no_whitespace, encoding='unicode', pretty_print=True)
def replace_arch_section(self, cr, uid, view_id, section_xpath, replacement, context=None):
# the root of the arch section shouldn't actually be replaced as it's
# not really editable itself, only the content truly is editable.
[view] = self.browse(cr, uid, [view_id], context=context)
arch = etree.fromstring(view.arch.encode('utf-8'))
# => get the replacement root
if not section_xpath:
root = arch
else:
# ensure there's only one match
[root] = arch.xpath(section_xpath)
root.text = replacement.text
root.tail = replacement.tail
# replace all children
del root[:]
for child in replacement:
root.append(copy.deepcopy(child))
return arch
def to_field_ref(self, cr, uid, el, context=None):
# filter out meta-information inserted in the document
attributes = dict((k, v) for k, v in el.items()
if not k.startswith('data-oe-'))
attributes['t-field'] = el.get('data-oe-expression')
out = html.html_parser.makeelement(el.tag, attrib=attributes)
out.tail = el.tail
return out
def save(self, cr, uid, res_id, value, xpath=None, context=None):
""" Update a view section. The view section may embed fields to write
:param str model:
:param int res_id:
:param str xpath: valid xpath to the tag to replace
"""
res_id = int(res_id)
arch_section = html.fromstring(
value, parser=html.HTMLParser(encoding='utf-8'))
if xpath is None:
# value is an embedded field on its own, not a view section
self.save_embedded_field(cr, uid, arch_section, context=context)
return
for el in self.extract_embedded_fields(cr, uid, arch_section, context=context):
self.save_embedded_field(cr, uid, el, context=context)
# transform embedded field back to t-field
el.getparent().replace(el, self.to_field_ref(cr, uid, el, context=context))
arch = self.replace_arch_section(cr, uid, res_id, xpath, arch_section, context=context)
self.write(cr, uid, res_id, {
'arch': self._pretty_arch(arch)
}, context=context)
view = self.browse(cr, openerp.SUPERUSER_ID, res_id, context=context)
if view.model_data_id:
view.model_data_id.write({'noupdate': True})