[FIX] move conversion code from ir.fields.converter into website.qweb structures

bzr revid: xmo@openerp.com-20131009133112-05dglhptiw019838
This commit is contained in:
Xavier Morel 2013-10-09 15:31:12 +02:00
parent a3f7cfd669
commit eaef36c910
7 changed files with 111 additions and 121 deletions

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import ir_fields
import view
import website
import ir_qweb
import test_models

View File

@ -1,87 +0,0 @@
# -*- coding: utf-8 -*-
from lxml import etree, html
from openerp.osv import orm, fields
from openerp.tools import ustr
class converter(orm.Model):
_inherit = 'ir.fields.converter'
def _html_to_integer(self, cr, uid, model, column, value, context=None):
return int(value.text_content().strip()), []
def _html_to_float(self, cr, uid, model, column, value, context=None):
return float(value.text_content().strip()), []
def _html_to_passthrough(self, cr, uid, model, column, value, context=None):
return value.text_content().strip(), []
_html_to_char = _html_to_date = _html_to_datetime = _html_to_passthrough
def _html_to_text(self, cr, uid, model, column, value, context=None):
return value.text_content(), []
def _html_to_selection(self, cr, uid, model, column, value, context=None):
text = value.text_content().strip()
selection = column.reify(cr, uid, model, column, context=context)
for k, v in selection:
if isinstance(v, str):
v = ustr(v)
if text == v:
return k, []
warning = u"No value found for label %s in selection %s" % (text, selection)
# FIXME: ?
return False, [Warning(warning.encode('utf-8'))]
def _html_to_many2one(self, cr, uid, model, column, value, context=None):
matches = self.pool[column._obj].name_search(
cr, uid, name=value.text_content().strip(), context=context)
# FIXME: more than one match, error reporting
return matches[0][0], []
def _html_to_html(self, cr, uid, model, column, value, context=None):
content = []
if value.text: content.append(value.text)
content.extend(html.tostring(child)
for child in value.iterchildren(tag=etree.Element))
return '\n'.join(content), []
class test_converter(orm.Model):
_name = 'website.converter.test'
_columns = {
'char': fields.char(),
'integer': fields.integer(),
'float': fields.float(),
'numeric': fields.float(digits=(16, 2)),
'many2one': fields.many2one('website.converter.test.sub'),
'binary': fields.binary(),
'date': fields.date(),
'datetime': fields.datetime(),
'selection': fields.selection([
(1, "réponse A"),
(2, "réponse B"),
(3, "réponse C"),
(4, "réponse D"),
]),
'selection_str': fields.selection([
('A', "Qu'il n'est pas arrivé à Toronto"),
('B', "Qu'il était supposé arriver à Toronto"),
('C', "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?"),
('D', "La réponse D"),
], string="Lorsqu'un pancake prend l'avion à destination de Toronto et "
"qu'il fait une escale technique à St Claude, on dit:"),
'html': fields.html(),
'text': fields.text(),
}
class test_converter_sub(orm.Model):
_name = 'website.converter.test.sub'
_columns = {
'name': fields.char(),
}

View File

@ -9,8 +9,10 @@ Also, adds methods to convert values back to openerp models.
import itertools
import werkzeug.utils
from lxml import etree, html
from openerp.osv import orm, fields
from openerp.tools import ustr
class QWeb(orm.AbstractModel):
""" QWeb object for rendering stuff in the website context
@ -37,26 +39,71 @@ class Field(orm.AbstractModel):
[('data-oe-translate', 1 if column.translate else 0)]
)
def value_from_string(self, value):
return value
def from_html(self, cr, uid, model, column, element, context=None):
return self.value_from_string(element.text_content().strip())
class Integer(orm.AbstractModel):
_name = 'website.qweb.field.integer'
_inherit = ['website.qweb.field']
value_from_string = int
class Float(orm.AbstractModel):
_name = 'website.qweb.field.float'
_inherit = ['website.qweb.field', 'ir.qweb.field.float']
value_from_string = float
class Text(orm.AbstractModel):
_name = 'website.qweb.field.text'
_inherit = ['website.qweb.field', 'ir.qweb.field.text']
def from_html(self, cr, uid, model, column, element, context=None):
return element.text_content()
class Selection(orm.AbstractModel):
_name = 'website.qweb.field.selection'
_inherit = ['website.qweb.field', 'ir.qweb.field.selection']
def from_html(self, cr, uid, model, column, element, context=None):
value = element.text_content().strip()
selection = column.reify(cr, uid, model, column, context=context)
for k, v in selection:
if isinstance(v, str):
v = ustr(v)
if value == v:
return k
raise ValueError(u"No value found for label %s in selection %s" % (
value, selection))
class ManyToOne(orm.AbstractModel):
_name = 'website.qweb.field.many2one'
_inherit = ['website.qweb.field', 'ir.qweb.field.many2one']
def from_html(self, cr, uid, model, column, element, context=None):
# FIXME: this behavior is really weird, what if the user wanted to edit the name of the related thingy? Should m2os really be editable without a widget?
matches = self.pool[column._obj].name_search(
cr, uid, name=element.text_content().strip(), context=context)
# FIXME: no match? More than 1 match?
assert len(matches) == 1
return matches[0][0]
class HTML(orm.AbstractModel):
_name = 'website.qweb.field.html'
_inherit = ['website.qweb.field', 'ir.qweb.field.html']
def from_html(self, cr, uid, model, column, element, context=None):
content = []
if element.text: content.append(element.text)
content.extend(html.tostring(child)
for child in element.iterchildren(tag=etree.Element))
return '\n'.join(content)
class Image(orm.AbstractModel):
"""
Widget options:

View File

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from openerp.osv import orm, fields
class test_converter(orm.Model):
_name = 'website.converter.test'
_columns = {
'char': fields.char(),
'integer': fields.integer(),
'float': fields.float(),
'numeric': fields.float(digits=(16, 2)),
'many2one': fields.many2one('website.converter.test.sub'),
'binary': fields.binary(),
'date': fields.date(),
'datetime': fields.datetime(),
'selection': fields.selection([
(1, "réponse A"),
(2, "réponse B"),
(3, "réponse C"),
(4, "réponse D"),
]),
'selection_str': fields.selection([
('A', "Qu'il n'est pas arrivé à Toronto"),
('B', "Qu'il était supposé arriver à Toronto"),
('C', "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?"),
('D', "La réponse D"),
], string="Lorsqu'un pancake prend l'avion à destination de Toronto et "
"qu'il fait une escale technique à St Claude, on dit:"),
'html': fields.html(),
'text': fields.text(),
}
class test_converter_sub(orm.Model):
_name = 'website.converter.test.sub'
_columns = {
'name': fields.char(),
}

View File

@ -60,11 +60,9 @@ class view(osv.osv):
field = el.get('data-oe-field')
column = Model._all_columns[field].column
convert = self.pool['ir.fields.converter'].to_field(
cr, uid, Model, column, fromtype="html", context=context)
value, warnings = convert(el)
# FIXME: report error
if warnings: return
converter = self.pool['website.qweb'].get_converter_for(
el.get('data-oe-type'))
value = converter.from_html(cr, uid, Model, column, el)
Model.write(cr, uid, [int(el.get('data-oe-id'))], {
field: value

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from collections import namedtuple
from functools import partial
from xml.dom.minidom import getDOMImplementation
@ -10,19 +9,10 @@ from openerp.tests import common
impl = getDOMImplementation()
document = impl.createDocument(None, None, None)
Request = namedtuple('Request', 'cr uid registry')
class RegistryProxy(object):
def __init__(self, func):
self.func = func
def __getitem__(self, name):
return self.func(name)
class TestConvertBack(common.TransactionCase):
def setUp(self):
super(TestConvertBack, self).setUp()
self.Converter = self.registry('ir.fields.converter')
def field_rountrip_result(self, field, value, expected):
model = 'website.converter.test'
Model = self.registry(model)
@ -36,7 +26,7 @@ class TestConvertBack(common.TransactionCase):
field_value = 'record.%s' % field
e.setAttribute('t-field', field_value)
rendered = self.registry('ir.qweb').render_tag_field(
rendered = self.registry('website.qweb').render_tag_field(
e, {'field': field_value}, '', {
'record': record,
})
@ -44,12 +34,11 @@ class TestConvertBack(common.TransactionCase):
rendered, parser=html.HTMLParser(encoding='utf-8'))
column = Model._all_columns[field].column
converter = self.registry('website.qweb').get_converter_for(
element.get('data-oe-type'))
from_html = self.Converter.to_field(
self.cr, self.uid, model, column, 'html')
value_back, warnings = from_html(element)
self.assertEqual(warnings, [])
value_back = converter.from_html(
self.cr, self.uid, model, column, element)
if isinstance(expected, str):
expected = expected.decode('utf-8')

View File

@ -31,8 +31,8 @@ class TestViewSaving(common.TransactionCase):
h.H3("Column 2"),
h.UL(
h.LI("Item 1"),
h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name'))),
h.LI(h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone')))
h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name', type='char'))),
h.LI(h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone', type='char')))
))
)
self.view_id = self.registry('ir.ui.view').create(self.cr, self.uid, {
@ -46,14 +46,15 @@ class TestViewSaving(common.TransactionCase):
self.cr, self.uid, self.arch, context=None)
expect = [
h.SPAN("My Company", attrs(model='res.company', id=1, field='name')),
h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone')),
h.SPAN("My Company", attrs(model='res.company', id=1, field='name', type='char')),
h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone', type='char')),
]
for actual, expected in itertools.izip_longest(fields, expect):
self.eq(actual, expected)
def test_embedded_save(self):
embedded = h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone'))
embedded = h.SPAN("+00 00 000 00 0 000", attrs(
model='res.company', id=1, field='phone', type='char'))
self.registry('ir.ui.view').save_embedded_field(self.cr, self.uid, embedded)
@ -118,8 +119,8 @@ class TestViewSaving(common.TransactionCase):
h.H3("Column 2"),
h.UL(
h.LI("Item 1"),
h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name'))),
h.LI(h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone')))
h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name', type='char'))),
h.LI(h.SPAN("+00 00 000 00 0 000", attrs(model='res.company', id=1, field='phone', type='char')))
))
))
@ -137,8 +138,8 @@ class TestViewSaving(common.TransactionCase):
h.H3("Column 2"),
h.UL(
h.LI("wob wob wob"),
h.LI(h.SPAN("Acme Corporation", attrs(model='res.company', id=1, field='name', expression="bob"))),
h.LI(h.SPAN("+12 3456789", attrs(model='res.company', id=1, field='phone', expression="edmund"))),
h.LI(h.SPAN("Acme Corporation", attrs(model='res.company', id=1, field='name', expression="bob", type='char'))),
h.LI(h.SPAN("+12 3456789", attrs(model='res.company', id=1, field='phone', expression="edmund", type='char'))),
)
), encoding='utf-8')
View.save(self.cr, self.uid, res_id=self.view_id, value=replacement,
@ -173,7 +174,7 @@ class TestViewSaving(common.TransactionCase):
node = html.tostring(h.SPAN(
"Acme Corporation",
attrs(model='res.company', id=company_id, field="name", expression='bob')))
attrs(model='res.company', id=company_id, field="name", expression='bob', type='char')))
self.registry('ir.ui.view').save(self.cr, self.uid, res_id=company_id,value=node)
@ -184,7 +185,9 @@ class TestViewSaving(common.TransactionCase):
def test_field_tail(self):
View = self.registry('ir.ui.view')
replacement = ET.tostring(
h.LI(h.SPAN("+12 3456789", attrs(model='res.company', id=1, field='phone', expression="edmund")),
h.LI(h.SPAN("+12 3456789", attrs(
model='res.company', id=1, type='char',
field='phone', expression="edmund")),
"whop whop"
), encoding="utf-8")
View.save(self.cr, self.uid, res_id = self.view_id, value=replacement,
@ -203,7 +206,7 @@ class TestViewSaving(common.TransactionCase):
h.H3("Column 2"),
h.UL(
h.LI("Item 1"),
h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name'))),
h.LI(h.SPAN("My Company", attrs(model='res.company', id=1, field='name', type='char'))),
h.LI(h.SPAN({'t-field': "edmund"}), "whop whop"),
))
)