[MIG] web_editor: migrate to new api

This commit is contained in:
fwi-odoo
2016-08-03 13:42:25 +02:00
committed by Thibault Delavallée
parent 65fbeb21f6
commit a32c1d3c8d
17 changed files with 194 additions and 219 deletions
+2
View File
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import controllers
import models
import tests
+3
View File
@@ -1,3 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'Web Editor',
'category': 'Hidden',
@@ -1 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import main
+34 -33
View File
@@ -1,14 +1,17 @@
# -*- coding: utf-8 -*-
from openerp.http import request, STATIC_CACHE
from openerp import http
import json
import io
from PIL import Image, ImageFont, ImageDraw
from openerp import tools
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import cStringIO
import werkzeug.wrappers
import time
import io
import json
import logging
import time
import werkzeug.wrappers
from PIL import Image, ImageFont, ImageDraw
from odoo.http import request
from odoo import http, tools
logger = logging.getLogger(__name__)
@@ -25,8 +28,6 @@ class Web_Editor(http.Controller):
#------------------------------------------------------
@http.route('/web_editor/field/html', type='http', auth="user")
def FieldTextHtml(self, model=None, res_id=None, field=None, callback=None, **kwargs):
cr, uid, context = request.cr, request.uid, request.context
kwargs.update(
model=model,
res_id=res_id,
@@ -39,17 +40,16 @@ class Web_Editor(http.Controller):
kwargs[k] = int(kwargs[k])
trans = dict(
lang=kwargs.get('lang', context.get('lang')),
lang=kwargs.get('lang', request.env.context.get('lang')),
translatable=kwargs.get('translatable'),
edit_translations=kwargs.get('edit_translations'),
editable=kwargs.get('enable_editor'))
context.update(trans)
kwargs.update(trans)
record = None
if model and kwargs.get('res_id'):
record = request.registry[model].browse(cr, uid, kwargs.get('res_id'), context)
record = request.env[model].with_context(trans).browse(kwargs.get('res_id'))
kwargs.update(content=record and getattr(record, field) or "")
@@ -141,23 +141,23 @@ class Web_Editor(http.Controller):
# the upload argument doesn't allow us to access the files if more than
# one file is uploaded, as upload references the first file
# therefore we have to recover the files from the request object
Attachments = request.registry['ir.attachment'] # registry for the attachment table
Attachments = request.env['ir.attachment'] # registry for the attachment table
uploads = []
message = None
if not upload: # no image provided, storing the link and the image name
name = url.split("/").pop() # recover filename
attachment_id = Attachments.create(request.cr, request.uid, {
attachment = Attachments.create({
'name': name,
'type': 'url',
'url': url,
'public': True,
'res_model': 'ir.ui.view',
}, request.context)
uploads += Attachments.read(request.cr, request.uid, [attachment_id], ['name', 'mimetype', 'checksum', 'url'], request.context)
})
uploads += attachment.read(['name', 'mimetype', 'checksum', 'url'])
else: # images provided
try:
attachment_ids = []
attachments = request.env['ir.attachment']
for c_file in request.httprequest.files.getlist('upload'):
data = c_file.read()
try:
@@ -172,15 +172,15 @@ class Web_Editor(http.Controller):
except IOError, e:
pass
attachment_id = Attachments.create(request.cr, request.uid, {
attachment = Attachments.create({
'name': c_file.filename,
'datas': data.encode('base64'),
'datas_fname': c_file.filename,
'public': True,
'res_model': 'ir.ui.view',
}, request.context)
attachment_ids.append(attachment_id)
uploads += Attachments.read(request.cr, request.uid, attachment_ids, ['name', 'mimetype', 'checksum', 'url'], request.context)
})
attachments += attachment
uploads += attachments.read(['name', 'mimetype', 'checksum', 'url'])
except Exception, e:
logger.exception("Failed to upload image to attachment")
message = unicode(e)
@@ -199,25 +199,26 @@ class Web_Editor(http.Controller):
Returns a dict mapping attachments which would not be removed (if any)
mapped to the views preventing their removal
"""
cr, uid, context = request.cr, request.uid, request.context
Attachment = request.registry['ir.attachment']
Views = request.registry['ir.ui.view']
Attachment = attachments_to_remove = request.env['ir.attachment']
Views = request.env['ir.ui.view']
attachments_to_remove = []
# views blocking removal of the attachment
removal_blocked_by = {}
for attachment in Attachment.browse(cr, uid, ids, context=context):
for attachment in Attachment.browse(ids):
# in-document URLs are html-escaped, a straight search will not
# find them
url = tools.html_escape(attachment.local_url)
ids = Views.search(cr, uid, ["|", ('arch_db', 'like', '"%s"' % url), ('arch_db', 'like', "'%s'" % url)], context=context)
views = Views.search([
"|",
('arch_db', 'like', '"%s"' % url),
('arch_db', 'like', "'%s'" % url)
])
if ids:
removal_blocked_by[attachment.id] = Views.read(
cr, uid, ids, ['name'], context=context)
if views:
removal_blocked_by[attachment.id] = views.read(['name'])
else:
attachments_to_remove.append(attachment.id)
attachments_to_remove += attachment
if attachments_to_remove:
Attachment.unlink(cr, uid, attachments_to_remove, context=context)
attachments_to_remove.unlink()
return removal_blocked_by
+2
View File
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import ir_attachment
import ir_qweb
import ir_ui_view
+10 -28
View File
@@ -1,36 +1,18 @@
# -*- coding: utf-8 -*-
import openerp
from openerp.osv import osv, fields
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import contextlib
from sys import maxint
from openerp.http import request
import datetime
import hashlib
import time
import os
from openerp.tools import html_escape as escape, ustr, image_resize_and_sharpen, image_save_for_web
from PIL import Image
import cStringIO
import logging
logger = logging.getLogger(__name__)
from odoo import api, models, fields
class ir_attachment(osv.osv):
class IrAttachment(models.Model):
_inherit = "ir.attachment"
def _local_url_get(self, cr, uid, ids, name, arg, context=None):
result = {}
for attach in self.browse(cr, uid, ids, context=context):
if attach.url:
result[attach.id] = attach.url
else:
result[attach.id] = '/web/image/%s?unique=%s' % (attach.id, attach.checksum)
return result
local_url = fields.Char("Attachment URL", compute='_compute_local_url')
_columns = {
'local_url': fields.function(_local_url_get, string="Attachment URL", type='char'),
}
@api.one
def _compute_local_url(self):
if self.url:
self.local_url = self.url
else:
self.local_url = '/web/image/%s?unique=%s' % (self.id, self.checksum)
+6 -4
View File
@@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-
from openerp.osv import orm
from openerp.http import request
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
from odoo.http import request
class ir_http(orm.AbstractModel):
class IrHttp(models.AbstractModel):
_inherit = 'ir.http'
def _dispatch(self):
@@ -13,4 +15,4 @@ class ir_http(orm.AbstractModel):
request.context['edit_translations'] = True
if request.context.get('lang') != "en_US" and 'translatable' not in request.context:
request.context['translatable'] = True
return super(ir_http, self)._dispatch()
return super(IrHttp, self)._dispatch()
+29 -44
View File
@@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
"""
Web_editor-context rendering needs to add some metadata to rendered and allow to edit fields,
as well as render a few fields differently.
Also, adds methods to convert values back to openerp models.
Also, adds methods to convert values back to Odoo models.
"""
import ast
@@ -22,22 +24,19 @@ import pytz
from dateutil import parser
from lxml import etree, html
from PIL import Image as I
import openerp.modules
import odoo.modules
from odoo import api
import openerp
from openerp.osv import orm, fields
from openerp.tools import ustr, DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
from openerp.tools import html_escape as escape
from openerp.addons.base.ir import ir_qweb
from odoo import api, models, fields
from odoo.tools import ustr
from odoo.tools import html_escape as escape
from odoo.addons.base.ir import ir_qweb
REMOTE_CONNECTION_TIMEOUT = 2.5
logger = logging.getLogger(__name__)
class QWeb(orm.AbstractModel):
class QWeb(models.AbstractModel):
""" QWeb object for rendering editor stuff
"""
_inherit = 'ir.qweb'
@@ -69,7 +68,7 @@ class QWeb(orm.AbstractModel):
#------------------------------------------------------
class Field(orm.AbstractModel):
class Field(models.AbstractModel):
_name = 'ir.qweb.field'
_inherit = 'ir.qweb.field'
@@ -98,14 +97,14 @@ class Field(orm.AbstractModel):
return self.value_from_string(element.text_content().strip())
class Integer(orm.AbstractModel):
class Integer(models.AbstractModel):
_name = 'ir.qweb.field.integer'
_inherit = 'ir.qweb.field.integer'
value_from_string = int
class Float(orm.AbstractModel):
class Float(models.AbstractModel):
_name = 'ir.qweb.field.float'
_inherit = 'ir.qweb.field.float'
@@ -117,7 +116,7 @@ class Float(orm.AbstractModel):
.replace(lang.decimal_point, '.'))
class ManyToOne(orm.AbstractModel):
class ManyToOne(models.AbstractModel):
_name = 'ir.qweb.field.many2one'
_inherit = 'ir.qweb.field.many2one'
@@ -146,7 +145,7 @@ class ManyToOne(orm.AbstractModel):
return None
class Contact(orm.AbstractModel):
class Contact(models.AbstractModel):
_name = 'ir.qweb.field.contact'
_inherit = 'ir.qweb.field.contact'
@@ -165,18 +164,7 @@ class Contact(orm.AbstractModel):
return node and node.__html__()
def parse_fuzzy(in_format, value):
day_first = in_format.find('%d') < in_format.find('%m')
if '%y' in in_format:
year_first = in_format.find('%y') < in_format.find('%d')
else:
year_first = in_format.find('%Y') < in_format.find('%d')
return parser.parse(value, dayfirst=day_first, yearfirst=year_first)
class Date(orm.AbstractModel):
class Date(models.AbstractModel):
_name = 'ir.qweb.field.date'
_inherit = 'ir.qweb.field.date'
@@ -192,11 +180,10 @@ class Date(orm.AbstractModel):
if not value:
return False
datetime.datetime.strptime(value, DEFAULT_SERVER_DATE_FORMAT)
return value
class DateTime(orm.AbstractModel):
class DateTime(models.AbstractModel):
_name = 'ir.qweb.field.datetime'
_inherit = 'ir.qweb.field.datetime'
@@ -205,13 +192,11 @@ class DateTime(orm.AbstractModel):
attrs = super(DateTime, self).attributes(record, field_name, options, values)
value = record[field_name]
if isinstance(value, basestring):
value = datetime.datetime.strptime(
value, DEFAULT_SERVER_DATETIME_FORMAT)
value = fields.Datetime.from_string(value)
if value:
# convert from UTC (server timezone) to user timezone
value = fields.datetime.context_timestamp(
self._cr, self._uid, timestamp=value, context=self.env.context)
value = value.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
value = fields.Datetime.context_timestamp(self, timestamp=value)
value = fields.Datetime.to_string(value)
attrs['data-oe-original'] = value
return attrs
@@ -240,10 +225,10 @@ class DateTime(orm.AbstractModel):
exc_info=True)
# format back to string
return dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
return fields.Datetime.to_string(dt)
class Text(orm.AbstractModel):
class Text(models.AbstractModel):
_name = 'ir.qweb.field.text'
_inherit = 'ir.qweb.field.text'
@@ -252,7 +237,7 @@ class Text(orm.AbstractModel):
return html_to_text(element)
class Selection(orm.AbstractModel):
class Selection(models.AbstractModel):
_name = 'ir.qweb.field.selection'
_inherit = 'ir.qweb.field.selection'
@@ -270,7 +255,7 @@ class Selection(orm.AbstractModel):
value, selection))
class HTML(orm.AbstractModel):
class HTML(models.AbstractModel):
_name = 'ir.qweb.field.html'
_inherit = 'ir.qweb.field.html'
@@ -284,7 +269,7 @@ class HTML(orm.AbstractModel):
return '\n'.join(content)
class Image(orm.AbstractModel):
class Image(models.AbstractModel):
"""
Widget options:
@@ -361,7 +346,7 @@ class Image(orm.AbstractModel):
if sep and sep != '/':
rest.replace(sep, '/')
path = openerp.modules.get_module_resource(
path = odoo.modules.get_module_resource(
match.group('module'), 'static', *(rest.split('/')))
if not path:
@@ -403,7 +388,7 @@ class Image(orm.AbstractModel):
return out.getvalue().encode('base64')
class Monetary(orm.AbstractModel):
class Monetary(models.AbstractModel):
_name = 'ir.qweb.field.monetary'
_inherit = 'ir.qweb.field.monetary'
@@ -417,7 +402,7 @@ class Monetary(orm.AbstractModel):
.replace(lang.decimal_point, '.'))
class Duration(orm.AbstractModel):
class Duration(models.AbstractModel):
_name = 'ir.qweb.field.duration'
_inherit = 'ir.qweb.field.duration'
@@ -435,14 +420,14 @@ class Duration(orm.AbstractModel):
return float(value)
class RelativeDatetime(orm.AbstractModel):
class RelativeDatetime(models.AbstractModel):
_name = 'ir.qweb.field.relative'
_inherit = 'ir.qweb.field.relative'
# get formatting from ir.qweb.field.relative but edition/save from datetime
class QwebView(orm.AbstractModel):
class QwebView(models.AbstractModel):
_name = 'ir.qweb.field.qweb'
_inherit = 'ir.qweb.field.qweb'
+6 -4
View File
@@ -3,14 +3,16 @@
from lxml import etree
from openerp import models, api
from openerp.tools.translate import encode, xml_translate, html_translate
from odoo import models, api
from odoo.tools.translate import encode, xml_translate, html_translate
def edit_translation_mapping(data):
data = dict(data, model=data['name'].partition(',')[0])
return '<span data-oe-model="%(model)s" data-oe-translation-id="%(id)s" data-oe-translation-state="%(state)s">%(value)s</span>' % data
class ir_translation(models.Model):
class IrTranslation(models.Model):
_inherit = 'ir.translation'
@api.model
@@ -18,7 +20,7 @@ class ir_translation(models.Model):
if self._context.get('edit_translations'):
self.insert_missing(field, records)
return edit_translation_mapping
return super(ir_translation, self)._get_terms_mapping(field, records)
return super(IrTranslation, self)._get_terms_mapping(field, records)
@api.multi
def save_html(self, value):
+30 -42
View File
@@ -1,40 +1,33 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import copy
import openerp
from openerp.exceptions import AccessError
from openerp.osv import osv
from lxml import etree, html
from openerp import api
from odoo.exceptions import AccessError
from odoo import api, models
class view(osv.osv):
class IrUiView(models.Model):
_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'):
@api.multi
def render(self, values=None, engine='ir.qweb'):
if values and 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)
self.check_access_rights('write')
self.check_access_rule('write')
except AccessError:
values['editable'] = False
return super(view, self).render(cr, uid, id_or_xml_id, values=values, engine=engine, context=context)
return super(IrUiView, self).render(values=values, engine=engine)
#------------------------------------------------------
# Save from html
#------------------------------------------------------
def extract_embedded_fields(self, cr, uid, arch, context=None):
@api.model
def extract_embedded_fields(self, arch):
return arch.xpath('//*[@data-oe-model != "ir.ui.view"]')
@api.model
@@ -62,12 +55,12 @@ class view(osv.osv):
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):
@api.multi
def replace_arch_section(self, section_xpath, replacement):
# 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'))
self.ensure_one()
arch = etree.fromstring(self.arch.encode('utf-8'))
# => get the replacement root
if not section_xpath:
root = arch
@@ -84,7 +77,8 @@ class view(osv.osv):
return arch
def to_field_ref(self, cr, uid, el, context=None):
@api.model
def to_field_ref(self, el):
# filter out meta-information inserted in the document
attributes = dict((k, v) for k, v in el.items()
if not k.startswith('data-oe-'))
@@ -94,34 +88,28 @@ class view(osv.osv):
out.tail = el.tail
return out
def save(self, cr, uid, res_id, value, xpath=None, context=None):
@api.multi
def save(self, value, xpath=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)
self.save_embedded_field(arch_section)
return
for el in self.extract_embedded_fields(cr, uid, arch_section, context=context):
self.save_embedded_field(cr, uid, el, context=context)
for el in self.extract_embedded_fields(arch_section):
self.save_embedded_field(el)
# transform embedded field back to t-field
el.getparent().replace(el, self.to_field_ref(cr, uid, el, context=context))
el.getparent().replace(el, self.to_field_ref(el))
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)
for view in self:
arch = view.replace_arch_section(xpath, arch_section)
view.write({'arch': view._pretty_arch(arch)})
view = self.browse(cr, openerp.SUPERUSER_ID, res_id, context=context)
if view.model_data_id:
view.model_data_id.write({'noupdate': True})
self.sudo().mapped('model_data_id').write({'noupdate': True})
+29 -31
View File
@@ -1,43 +1,41 @@
# -*- coding: utf-8 -*-
from openerp.osv import orm, fields
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields
class test_converter(orm.Model):
class ConverterTest(models.Model):
_name = 'web_editor.converter.test'
# disable translation export for those brilliant field labels and values
_translate = False
_columns = {
'char': fields.char(),
'integer': fields.integer(),
'float': fields.float(),
'numeric': fields.float(digits=(16, 2)),
'many2one': fields.many2one('web_editor.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=u"Lorsqu'un pancake prend l'avion à destination de Toronto et "
u"qu'il fait une escale technique à St Claude, on dit:"),
'html': fields.html(),
'text': fields.text(),
}
char = fields.Char()
integer = fields.Integer()
float = fields.Float()
numeric = fields.Float(digits=(16, 2))
many2one = fields.Many2one('web_editor.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=u"Lorsqu'un pancake prend l'avion à destination de Toronto et "
u"qu'il fait une escale technique à St Claude, on dit:")
html = fields.Html()
text = fields.Text()
class test_converter_sub(orm.Model):
class ConverterTestSub(models.Model):
_name = 'web_editor.converter.test.sub'
_columns = {
'name': fields.char(),
}
name = fields.Char()
+2 -2
View File
@@ -110,7 +110,7 @@
<span class="text-muted">— or — </span>
<label for="iamgeurl">Add an image URL</label>
<div class="form-group btn-group">
<input class="form-control url pull-left" id="iamgeurl" name="url" placeholder="http://openerp.com/logo.png" style="width: 320px;" type="text"/>
<input class="form-control url pull-left" id="iamgeurl" name="url" placeholder="https://www.odoo.com/logo.png" style="width: 320px;" type="text"/>
<button class="btn btn-default" type="submit">Add</button>
</div>
</div>
@@ -238,7 +238,7 @@
<label class="control-label" for="link-external">URL or Email Address
</label>
</h4>
<input class="form-control url email-address url-source" id="link-external" placeholder="http://openerp.com" type="text"/>
<input class="form-control url email-address url-source" id="link-external" placeholder="https://www.odoo.com" type="text"/>
</li>
</ul>
<div class="form-horizontal link-style">
+2
View File
@@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import test_ui
import test_converter
+4 -2
View File
@@ -1,12 +1,14 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import textwrap
import unittest
from lxml import etree, html
from lxml.builder import E
from openerp.tests import common
from openerp.addons.web_editor.models.ir_qweb import html_to_text
from odoo.tests import common
from odoo.addons.web_editor.models.ir_qweb import html_to_text
class TestHTMLToText(unittest.TestCase):
+5 -2
View File
@@ -1,7 +1,10 @@
import openerp.tests
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo.tests
class TestUi(openerp.tests.HttpCase):
class TestUi(odoo.tests.HttpCase):
post_install = True
at_install = False
+2 -2
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<odoo>
<template id="layout" name="Editor layout">&lt;!DOCTYPE html&gt;
<html t-att-lang="lang and lang.replace('_', '-')"
@@ -66,4 +66,4 @@
</t>
</template>
</openerp>
</odoo>
+25 -25
View File
@@ -7,8 +7,11 @@ from lxml.html import builder as h
from openerp.tests import common
def attrs(**kwargs):
return dict(('data-oe-%s' % key, str(value)) for key, value in kwargs.iteritems())
class TestViewSaving(common.TransactionCase):
def eq(self, a, b):
self.assertEqual(a.tag, b.tag)
@@ -42,8 +45,7 @@ class TestViewSaving(common.TransactionCase):
})
def test_embedded_extraction(self):
fields = self.registry('ir.ui.view').extract_embedded_fields(
self.cr, self.uid, self.arch, context=None)
fields = self.env['ir.ui.view'].extract_embedded_fields(self.arch)
expect = [
h.SPAN("My Company", attrs(model='res.company', id=1, field='name', type='char')),
@@ -56,7 +58,7 @@ class TestViewSaving(common.TransactionCase):
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)
self.env['ir.ui.view'].save_embedded_field(embedded)
company = self.registry('res.company').browse(self.cr, self.uid, 1)
self.assertEqual(company.phone, "+00 00 000 00 0 000")
@@ -66,37 +68,37 @@ class TestViewSaving(common.TransactionCase):
e1 = h.SPAN("My Company", attrs(model='res.company', id=1, field='name'))
e2 = h.SPAN("Leeroy Jenkins", attrs(model='res.company', id=1, field='name'))
View = self.registry('ir.ui.view')
View = self.env['ir.ui.view']
View.save_embedded_field(self.cr, self.uid, e1)
View.save_embedded_field(e1)
# FIXME: more precise exception
with self.assertRaises(Exception):
View.save_embedded_field(self.cr, self.uid, e2)
View.save_embedded_field(e2)
def test_embedded_to_field_ref(self):
View = self.registry('ir.ui.view')
View = self.env['ir.ui.view']
embedded = h.SPAN("My Company", attrs(expression="bob"))
self.eq(
View.to_field_ref(self.cr, self.uid, embedded, context=None),
View.to_field_ref(embedded),
h.SPAN({'t-field': 'bob'})
)
def test_to_field_ref_keep_attributes(self):
View = self.registry('ir.ui.view')
View = self.env['ir.ui.view']
att = attrs(expression="bob", model="res.company", id=1, field="name")
att['id'] = "whop"
att['class'] = "foo bar"
embedded = h.SPAN("My Company", att)
self.eq(View.to_field_ref(self.cr, self.uid, embedded, context=None),
self.eq(View.to_field_ref(embedded),
h.SPAN({'t-field': 'bob', 'class': 'foo bar', 'id': 'whop'}))
def test_replace_arch(self):
replacement = h.P("Wheee")
result = self.registry('ir.ui.view').replace_arch_section(
self.cr, self.uid, self.view_id, None, replacement)
self.cr, self.uid, [self.view_id], None, replacement)
self.eq(result, h.DIV("Wheee"))
@@ -104,7 +106,7 @@ class TestViewSaving(common.TransactionCase):
replacement = h.DIV(h.P("Wheee"))
result = self.registry('ir.ui.view').replace_arch_section(
self.cr, self.uid, self.view_id, None, replacement)
self.cr, self.uid, [self.view_id], None, replacement)
self.eq(result, replacement)
@@ -112,7 +114,7 @@ class TestViewSaving(common.TransactionCase):
replacement = h.H1("I am the greatest title alive!")
result = self.registry('ir.ui.view').replace_arch_section(
self.cr, self.uid, self.view_id, '/div/div[1]/h3',
self.cr, self.uid, [self.view_id], '/div/div[1]/h3',
replacement)
self.eq(result, h.DIV(
@@ -134,12 +136,12 @@ class TestViewSaving(common.TransactionCase):
def test_multiple_xpath_matches(self):
with self.assertRaises(ValueError):
self.registry('ir.ui.view').replace_arch_section(
self.cr, self.uid, self.view_id, '/div/div/h3',
self.cr, self.uid, [self.view_id], '/div/div/h3',
h.H6("Lol nope"))
def test_save(self):
Company = self.registry('res.company')
View = self.registry('ir.ui.view')
View = self.env['ir.ui.view']
replacement = ET.tostring(h.DIV(
h.H3("Column 2"),
@@ -149,14 +151,13 @@ class TestViewSaving(common.TransactionCase):
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,
xpath='/div/div[2]')
View.browse(self.view_id).save(value=replacement, xpath='/div/div[2]')
company = Company.browse(self.cr, self.uid, 1)
self.assertEqual(company.name, "Acme Corporation")
self.assertEqual(company.phone, "+12 3456789")
self.eq(
ET.fromstring(View.browse(self.cr, self.uid, self.view_id).arch.encode('utf-8')),
ET.fromstring(View.browse(self.view_id).arch.encode('utf-8')),
h.DIV(
h.DIV(
h.H3("Column 1"),
@@ -180,7 +181,7 @@ class TestViewSaving(common.TransactionCase):
'arch':'<t><p><h1>hello world</h1></p></t>',
'type':'qweb'
})
view = self.registry('ir.ui.view').browse(self.cr, self.uid, view_id)
view = self.env['ir.ui.view'].browse(view_id)
# script and style text nodes should not escaped client side
replacement = '<script>1 && "hello & world"</script>'
view.save(replacement, xpath='/t/p/h1')
@@ -212,26 +213,25 @@ class TestViewSaving(common.TransactionCase):
node = html.tostring(h.SPAN(
"Acme Corporation",
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)
View = self.env['ir.ui.view']
View.browse(company_id).save(value=node)
company = Company.browse(self.cr, self.uid, company_id)
self.assertEqual(company.name, "Acme Corporation")
def test_field_tail(self):
View = self.registry('ir.ui.view')
View = self.env['ir.ui.view']
replacement = ET.tostring(
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,
xpath='/div/div[2]/ul/li[3]')
View.browse(self.view_id).save(value=replacement, xpath='/div/div[2]/ul/li[3]')
self.eq(
ET.fromstring(View.browse(self.cr, self.uid, self.view_id).arch.encode('utf-8')),
ET.fromstring(View.browse(self.view_id).arch.encode('utf-8')),
h.DIV(
h.DIV(
h.H3("Column 1"),