[MERGE] Forward-port saas-4 bugfixes up to ad4c6ca

This commit is contained in:
Olivier Dony 2014-06-12 18:54:36 +02:00
commit f15cbd6520
21 changed files with 1522 additions and 1456 deletions

View File

@ -580,7 +580,14 @@ class account_account(osv.osv):
pass pass
if name: if name:
if operator not in expression.NEGATIVE_TERM_OPERATORS: if operator not in expression.NEGATIVE_TERM_OPERATORS:
ids = self.search(cr, user, ['|', ('code', '=like', name+"%"), '|', ('shortcut', '=', name), ('name', operator, name)]+args, limit=limit) plus_percent = lambda n: n+'%'
code_op, code_conv = {
'ilike': ('=ilike', plus_percent),
'like': ('=like', plus_percent),
}.get(operator, (operator, lambda n: n))
ids = self.search(cr, user, ['|', ('code', code_op, code_conv(name)), '|', ('shortcut', '=', name), ('name', operator, name)]+args, limit=limit)
if not ids and len(name.split()) >= 2: if not ids and len(name.split()) >= 2:
#Separating code and name of account for searching #Separating code and name of account for searching
operand1,operand2 = name.split(' ',1) #name can contain spaces e.g. OpenERP S.A. operand1,operand2 = name.split(' ',1) #name can contain spaces e.g. OpenERP S.A.
@ -2918,7 +2925,7 @@ class account_fiscal_position_template(osv.osv):
'chart_template_id': fields.many2one('account.chart.template', 'Chart Template', required=True), 'chart_template_id': fields.many2one('account.chart.template', 'Chart Template', required=True),
'account_ids': fields.one2many('account.fiscal.position.account.template', 'position_id', 'Account Mapping'), 'account_ids': fields.one2many('account.fiscal.position.account.template', 'position_id', 'Account Mapping'),
'tax_ids': fields.one2many('account.fiscal.position.tax.template', 'position_id', 'Tax Mapping'), 'tax_ids': fields.one2many('account.fiscal.position.tax.template', 'position_id', 'Tax Mapping'),
'note': fields.text('Notes', translate=True), 'note': fields.text('Notes'),
} }
def generate_fiscal_position(self, cr, uid, chart_temp_id, tax_template_ref, acc_template_ref, company_id, context=None): def generate_fiscal_position(self, cr, uid, chart_temp_id, tax_template_ref, acc_template_ref, company_id, context=None):

View File

@ -579,6 +579,9 @@ class account_move_line(osv.osv):
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'account_move_line_journal_id_period_id_index\'') cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'account_move_line_journal_id_period_id_index\'')
if not cr.fetchone(): if not cr.fetchone():
cr.execute('CREATE INDEX account_move_line_journal_id_period_id_index ON account_move_line (journal_id, period_id)') cr.execute('CREATE INDEX account_move_line_journal_id_period_id_index ON account_move_line (journal_id, period_id)')
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('account_move_line_date_id_index',))
if not cr.fetchone():
cr.execute('CREATE INDEX account_move_line_date_id_index ON account_move_line (date DESC, id desc)')
return res return res
def _check_no_view(self, cr, uid, ids, context=None): def _check_no_view(self, cr, uid, ids, context=None):

View File

@ -33,7 +33,7 @@ class account_fiscal_position(osv.osv):
'company_id': fields.many2one('res.company', 'Company'), 'company_id': fields.many2one('res.company', 'Company'),
'account_ids': fields.one2many('account.fiscal.position.account', 'position_id', 'Account Mapping'), 'account_ids': fields.one2many('account.fiscal.position.account', 'position_id', 'Account Mapping'),
'tax_ids': fields.one2many('account.fiscal.position.tax', 'position_id', 'Tax Mapping'), 'tax_ids': fields.one2many('account.fiscal.position.tax', 'position_id', 'Tax Mapping'),
'note': fields.text('Notes', translate=True), 'note': fields.text('Notes'),
} }
_defaults = { _defaults = {

View File

@ -334,7 +334,7 @@
<field name="writeoff_amount" widget="monetary" options="{'currency_field': 'currency_id'}"/> <field name="writeoff_amount" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="payment_option" required="1" attrs="{'invisible':[('writeoff_amount','=',0)]}"/> <field name="payment_option" required="1" attrs="{'invisible':[('writeoff_amount','=',0)]}"/>
<field name="writeoff_acc_id" <field name="writeoff_acc_id"
attrs="{'invisible':['|', ('payment_option','!=','with_writeoff'), ('writeoff_amount','=',0)], 'required':[('payment_option','=','with_writeoff')]}" attrs="{'invisible':['|', ('payment_option','!=','with_writeoff'), ('writeoff_amount','=',0)], 'required':[('payment_option','=','with_writeoff'), ('writeoff_amount','!=',0)]}"
domain="[('type','=','other')]"/> domain="[('type','=','other')]"/>
<field name="comment" <field name="comment"
attrs="{'invisible':['|', ('payment_option','!=','with_writeoff'), ('writeoff_amount','=',0)]}"/> attrs="{'invisible':['|', ('payment_option','!=','with_writeoff'), ('writeoff_amount','=',0)]}"/>

View File

@ -214,6 +214,7 @@ class base_action_rule(osv.osv):
""" Wrap the methods `create` and `write` of the models specified by """ Wrap the methods `create` and `write` of the models specified by
the rules given by `ids` (or all existing rules if `ids` is `None`.) the rules given by `ids` (or all existing rules if `ids` is `None`.)
""" """
updated = False
if ids is None: if ids is None:
ids = self.search(cr, SUPERUSER_ID, []) ids = self.search(cr, SUPERUSER_ID, [])
for action_rule in self.browse(cr, SUPERUSER_ID, ids): for action_rule in self.browse(cr, SUPERUSER_ID, ids):
@ -223,20 +224,21 @@ class base_action_rule(osv.osv):
model_obj.create = self._wrap_create(model_obj.create, model) model_obj.create = self._wrap_create(model_obj.create, model)
model_obj.write = self._wrap_write(model_obj.write, model) model_obj.write = self._wrap_write(model_obj.write, model)
model_obj.base_action_ruled = True model_obj.base_action_ruled = True
return True updated = True
return updated
def create(self, cr, uid, vals, context=None): def create(self, cr, uid, vals, context=None):
res_id = super(base_action_rule, self).create(cr, uid, vals, context=context) res_id = super(base_action_rule, self).create(cr, uid, vals, context=context)
self._register_hook(cr, [res_id]) if self._register_hook(cr, [res_id]):
openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname)
return res_id return res_id
def write(self, cr, uid, ids, vals, context=None): def write(self, cr, uid, ids, vals, context=None):
if isinstance(ids, (int, long)): if isinstance(ids, (int, long)):
ids = [ids] ids = [ids]
super(base_action_rule, self).write(cr, uid, ids, vals, context=context) super(base_action_rule, self).write(cr, uid, ids, vals, context=context)
self._register_hook(cr, ids) if self._register_hook(cr, ids):
openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname)
return True return True
def onchange_model_id(self, cr, uid, ids, model_id, context=None): def onchange_model_id(self, cr, uid, ids, model_id, context=None):
@ -266,7 +268,10 @@ class base_action_rule(osv.osv):
action_ids = self.search(cr, uid, action_dom, context=context) action_ids = self.search(cr, uid, action_dom, context=context)
for action in self.browse(cr, uid, action_ids, context=context): for action in self.browse(cr, uid, action_ids, context=context):
now = datetime.now() now = datetime.now()
last_run = get_datetime(action.last_run) if action.last_run else False if action.last_run:
last_run = get_datetime(action.last_run)
else:
last_run = datetime.utcfromtimestamp(0)
# retrieve all the records that satisfy the action's condition # retrieve all the records that satisfy the action's condition
model = self.pool[action.model_id.model] model = self.pool[action.model_id.model]
@ -297,11 +302,16 @@ class base_action_rule(osv.osv):
if not record_dt: if not record_dt:
continue continue
action_dt = self._check_delay(cr, uid, action, record, record_dt, context=context) action_dt = self._check_delay(cr, uid, action, record, record_dt, context=context)
if last_run and (last_run <= action_dt < now) or (action_dt < now): if last_run <= action_dt < now:
try: try:
context = dict(context or {}, action=True)
self._process(cr, uid, action, [record.id], context=context) self._process(cr, uid, action, [record.id], context=context)
except Exception: except Exception:
import traceback import traceback
_logger.error(traceback.format_exc()) _logger.error(traceback.format_exc())
action.write({'last_run': now.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}) action.write({'last_run': now.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
if automatic:
# auto-commit for batch processing
cr.commit()

View File

@ -10,7 +10,7 @@
<field eval="False" name="doall"/> <field eval="False" name="doall"/>
<field eval="'base.action.rule'" name="model"/> <field eval="'base.action.rule'" name="model"/>
<field eval="'_check'" name="function"/> <field eval="'_check'" name="function"/>
<field eval="'()'" name="args"/> <field eval="'(True,)'" name="args"/>
</record> </record>
</data> </data>

View File

@ -129,6 +129,36 @@ class gamification_goal_definition(osv.Model):
user = self.pool.get('res.users').browse(cr, uid, uid, context=context) user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
return self.pool.get('mail.followers').search(cr, uid, [('res_model', '=', model_name), ('partner_id', '=', user.partner_id.id)], count=True, context=context) return self.pool.get('mail.followers').search(cr, uid, [('res_model', '=', model_name), ('partner_id', '=', user.partner_id.id)], count=True, context=context)
def _check_domain_validity(self, cr, uid, ids, context=None):
# take admin as should always be present
superuser = self.pool['res.users'].browse(cr, uid, SUPERUSER_ID, context=context)
for definition in self.browse(cr, uid, ids, context=context):
if definition.computation_mode not in ('count', 'sum'):
continue
obj = self.pool[definition.model_id.model]
try:
domain = safe_eval(definition.domain, {'user': superuser})
# demmy search to make sure the domain is valid
obj.search(cr, uid, domain, context=context, count=True)
except (ValueError, SyntaxError), e:
msg = e.message or (e.msg + '\n' + e.text)
raise osv.except_osv(_('Error!'),_("The domain for the definition %s seems incorrect, please check it.\n\n%s" % (definition.name, msg)))
return True
def create(self, cr, uid, vals, context=None):
res_id = super(gamification_goal_definition, self).create(cr, uid, vals, context=context)
if vals.get('computation_mode') in ('count', 'sum'):
self._check_domain_validity(cr, uid, [res_id], context=context)
return res_id
def write(self, cr, uid, ids, vals, context=None):
res = super(gamification_goal_definition, self).write(cr, uid, ids, vals, context=context)
if vals.get('computation_mode', 'count') in ('count', 'sum') and (vals.get('domain') or vals.get('model_id')):
self._check_domain_validity(cr, uid, ids, context=context)
return res
class gamification_goal(osv.Model): class gamification_goal(osv.Model):

View File

@ -139,7 +139,7 @@
</page> </page>
<page string="Attendances" groups="base.group_hr_attendance"> <page string="Attendances" groups="base.group_hr_attendance">
<group> <group>
<field context="{'employee_id': employee_id, 'user_id':user_id}" name="attendances_ids" nolabel="1"> <field context="{'default_employee_id': employee_id, 'user_id':user_id}" name="attendances_ids" nolabel="1">
<tree string="Attendances" editable="bottom"> <tree string="Attendances" editable="bottom">
<field name="name"/> <field name="name"/>
<field name="action"/> <field name="action"/>

File diff suppressed because it is too large Load Diff

View File

@ -72,6 +72,7 @@ class account_fiscal_position(osv.osv):
_inherit = 'account.fiscal.position' _inherit = 'account.fiscal.position'
_columns = { _columns = {
'name': fields.char('Fiscal Position', size=64, required=True, translate=True), 'name': fields.char('Fiscal Position', size=64, required=True, translate=True),
'note': fields.text('Notes', translate=True),
} }
@ -79,6 +80,7 @@ class account_fiscal_position_template(osv.osv):
_inherit = 'account.fiscal.position.template' _inherit = 'account.fiscal.position.template'
_columns = { _columns = {
'name': fields.char('Fiscal Position Template', size=64, required=True, translate=True), 'name': fields.char('Fiscal Position Template', size=64, required=True, translate=True),
'note': fields.text('Notes', translate=True),
} }

View File

@ -46,7 +46,7 @@ class WebsiteSurvey(http.Controller):
# In case of auth required, block public user # In case of auth required, block public user
if survey.auth_required and uid == request.website.user_id.id: if survey.auth_required and uid == request.website.user_id.id:
return request.website.render("website.403") return request.website.render("survey.auth_required", {'survey': survey})
# In case of non open surveys # In case of non open surveys
if survey.stage_id.closed: if survey.stage_id.closed:

View File

@ -14,18 +14,7 @@
</record> </record>
<!-- Record rules --> <!-- Record rules -->
<record id="survey_public_access" model="ir.rule"> <record id="survey_users_access" model="ir.rule">
<field name="name">Public access to surveys</field>
<field name="model_id" ref="survey.model_survey_survey"/>
<field name="domain_force">[('auth_required', '=', False)]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field eval="0" name="perm_unlink"/>
<field eval="0" name="perm_write"/>
<field eval="1" name="perm_read"/>
<field eval="0" name="perm_create"/>
</record>
<record id="survey_rule" model="ir.rule">
<field name="name">Access to survey for regular users</field> <field name="name">Access to survey for regular users</field>
<field name="model_id" ref="survey.model_survey_survey"/> <field name="model_id" ref="survey.model_survey_survey"/>
<field name="domain_force">[('stage_id.closed', '=', False)]</field> <field name="domain_force">[('stage_id.closed', '=', False)]</field>
@ -36,7 +25,7 @@
<field eval="0" name="perm_create"/> <field eval="0" name="perm_create"/>
</record> </record>
<record id="survey_rule_manager" model="ir.rule"> <record id="survey_manager_access" model="ir.rule">
<field name="name">Survey Manager access rights</field> <field name="name">Survey Manager access rights</field>
<field name="model_id" ref="survey.model_survey_survey"/> <field name="model_id" ref="survey.model_survey_survey"/>
<field name="domain_force">[(1, '=', 1)]</field> <field name="domain_force">[(1, '=', 1)]</field>
@ -47,7 +36,7 @@
<field eval="1" name="perm_create"/> <field eval="1" name="perm_create"/>
</record> </record>
<record id="survey_public_access" model="ir.rule"> <record id="survey_input_public_access" model="ir.rule">
<field name="name">Public access to user_input</field> <field name="name">Public access to user_input</field>
<field name="model_id" ref="survey.model_survey_user_input"/> <field name="model_id" ref="survey.model_survey_user_input"/>
<field name="domain_force">[('create_uid', '=', user.id)]</field> <field name="domain_force">[('create_uid', '=', user.id)]</field>
@ -58,7 +47,7 @@
<field eval="0" name="perm_create"/> <field eval="0" name="perm_create"/>
</record> </record>
<record id="survey_rule" model="ir.rule"> <record id="survey_input_users_access" model="ir.rule">
<field name="name">Access to user_input for regular users</field> <field name="name">Access to user_input for regular users</field>
<field name="model_id" ref="survey.model_survey_user_input"/> <field name="model_id" ref="survey.model_survey_user_input"/>
<field name="domain_force">[('create_uid', '=', user.id)]</field> <field name="domain_force">[('create_uid', '=', user.id)]</field>
@ -69,7 +58,7 @@
<field eval="0" name="perm_create"/> <field eval="0" name="perm_create"/>
</record> </record>
<record id="survey_rule_manager" model="ir.rule"> <record id="survey_input_manager_access" model="ir.rule">
<field name="name">Survey Manager access rights</field> <field name="name">Survey Manager access rights</field>
<field name="model_id" ref="survey.model_survey_user_input"/> <field name="model_id" ref="survey.model_survey_user_input"/>
<field name="domain_force">[(1, '=', 1)]</field> <field name="domain_force">[(1, '=', 1)]</field>

View File

@ -26,7 +26,6 @@ $(document).ready(function () {
var question_id = $(pagination).attr("data-question_id"); var question_id = $(pagination).attr("data-question_id");
var limit = $(pagination).attr("data-record_limit"); //Number of Record Par Page. If you want to change number of record per page, change record_limit in pagination template. var limit = $(pagination).attr("data-record_limit"); //Number of Record Par Page. If you want to change number of record per page, change record_limit in pagination template.
$('#table_question_'+ question_id +' tbody tr:lt('+limit+')').removeClass('hidden'); $('#table_question_'+ question_id +' tbody tr:lt('+limit+')').removeClass('hidden');
$('#pagination_'+question_id+' li:first').addClass('active');
$('#pagination_'+question_id+' li a').click(function(event){ $('#pagination_'+question_id+' li a').click(function(event){
event.preventDefault(); event.preventDefault();
$('#pagination_'+question_id+' li').removeClass('active'); $('#pagination_'+question_id+' li').removeClass('active');
@ -41,6 +40,7 @@ $(document).ready(function () {
$('#table_question_'+question_id+' tbody tr:lt('+ limit * num +'):gt('+min+')').removeClass('hidden'); $('#table_question_'+question_id+' tbody tr:lt('+ limit * num +'):gt('+min+')').removeClass('hidden');
} }
}); });
$('#pagination_'+question_id+' li:first').addClass('active').find('a').click();
}); });
//initialize MultiBar Chart //initialize MultiBar Chart

View File

@ -31,6 +31,20 @@
</t> </t>
</template> </template>
<!-- Message when a login is required -->
<template id="auth_required" name="Login required for this survey">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<div class="jumbotron mt32">
<h1>Login required</h1>
<p>This survey is open only to registered people. Please <a t-attf-href="/web/login?redirect=%2Fsurvey%2Fstart%2F#{ slug(survey) }">log in</a>.</p>
</div>
</div>
</div>
</t>
</template>
<!-- Message when the survey has no pages --> <!-- Message when the survey has no pages -->
<template id="nopages" name="Survey has no pages"> <template id="nopages" name="Survey has no pages">
<t t-call="website.layout"> <t t-call="website.layout">

View File

@ -25,6 +25,7 @@ import openerp.modules
import openerp import openerp
from openerp.osv import orm, fields from openerp.osv import orm, fields
from openerp.tools import ustr, DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT from openerp.tools import ustr, DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
from openerp.tools import html_escape as escape
from openerp.addons.web.http import request from openerp.addons.web.http import request
from openerp.addons.base.ir import ir_qweb from openerp.addons.base.ir import ir_qweb
@ -276,7 +277,7 @@ class Image(orm.AbstractModel):
url_params[options_key] = options[options_key] url_params[options_key] = options[options_key]
return ir_qweb.HTMLSafe('<img class="%s" src="/website/image?%s"/>' % ( return ir_qweb.HTMLSafe('<img class="%s" src="/website/image?%s"/>' % (
' '.join(itertools.imap(werkzeug.utils.escape, classes)), ' '.join(itertools.imap(escape, classes)),
werkzeug.urls.url_encode(url_params) werkzeug.urls.url_encode(url_params)
)) ))

View File

@ -27,6 +27,7 @@ except ImportError:
import openerp import openerp
from openerp.osv import orm, osv, fields from openerp.osv import orm, osv, fields
from openerp.tools import html_escape as escape
from openerp.tools.safe_eval import safe_eval from openerp.tools.safe_eval import safe_eval
from openerp.addons.web.http import request from openerp.addons.web.http import request
@ -710,7 +711,7 @@ class ir_attachment(osv.osv):
for attachment in self.browse(cr, uid, ids, context=context): for attachment in self.browse(cr, uid, ids, context=context):
# in-document URLs are html-escaped, a straight search will not # in-document URLs are html-escaped, a straight search will not
# find them # find them
url = werkzeug.utils.escape(attachment.website_url) url = escape(attachment.website_url)
ids = Views.search(cr, uid, ["|", ('arch', 'like', '"%s"' % url), ('arch', 'like', "'%s'" % url)], context=context) ids = Views.search(cr, uid, ["|", ('arch', 'like', '"%s"' % url), ('arch', 'like', "'%s'" % url)], context=context)
if ids: if ids:

View File

@ -24,9 +24,9 @@ import datetime
import re import re
import pytz import pytz
import werkzeug.utils
import openerp import openerp
import openerp.tools
from openerp.addons.web import http from openerp.addons.web import http
from openerp.addons.web.http import request from openerp.addons.web.http import request
@ -150,7 +150,7 @@ class website_event(http.Controller):
if post.get('tag_'+str(tag.id)): if post.get('tag_'+str(tag.id)):
tags.append(tag.id) tags.append(tag.id)
e = werkzeug.utils.escape e = openerp.tools.escape
track_description = '''<section data-snippet-id="text-block"> track_description = '''<section data-snippet-id="text-block">
<div class="container"> <div class="container">
<div class="row"> <div class="row">

View File

@ -16,7 +16,6 @@ from urlparse import urlparse
import babel import babel
import babel.dates import babel.dates
import werkzeug
from PIL import Image from PIL import Image
import openerp.http import openerp.http
@ -26,6 +25,7 @@ import openerp.tools.lru
from openerp.http import request from openerp.http import request
from openerp.tools.safe_eval import safe_eval as eval from openerp.tools.safe_eval import safe_eval as eval
from openerp.osv import osv, orm, fields from openerp.osv import osv, orm, fields
from openerp.tools import html_escape as escape
from openerp.tools.translate import _ from openerp.tools.translate import _
from openerp import SUPERUSER_ID from openerp import SUPERUSER_ID
@ -269,14 +269,14 @@ class QWeb(orm.AbstractModel):
for attribute in self._render_att: for attribute in self._render_att:
if attribute_name[2:].startswith(attribute): if attribute_name[2:].startswith(attribute):
att, val = self._render_att[attribute](self, element, attribute_name, attribute_value, qwebcontext) att, val = self._render_att[attribute](self, element, attribute_name, attribute_value, qwebcontext)
generated_attributes += val and ' %s="%s"' % (att, werkzeug.utils.escape(val)) or " " generated_attributes += val and ' %s="%s"' % (att, escape(val)) or " "
break break
else: else:
if attribute_name[2:] in self._render_tag: if attribute_name[2:] in self._render_tag:
t_render = attribute_name[2:] t_render = attribute_name[2:]
template_attributes[attribute_name[2:]] = attribute_value template_attributes[attribute_name[2:]] = attribute_value
else: else:
generated_attributes += ' %s="%s"' % (attribute_name, werkzeug.utils.escape(attribute_value)) generated_attributes += ' %s="%s"' % (attribute_name, escape(attribute_value))
if 'debug' in template_attributes: if 'debug' in template_attributes:
debugger = template_attributes.get('debug', 'pdb') debugger = template_attributes.get('debug', 'pdb')
@ -489,7 +489,7 @@ class FieldConverter(osv.AbstractModel):
""" """
Generates the metadata attributes (prefixed by ``data-oe-`` for the Generates the metadata attributes (prefixed by ``data-oe-`` for the
root node of the field conversion. Attribute values are escaped by the root node of the field conversion. Attribute values are escaped by the
parent using ``werkzeug.utils.escape``. parent.
The default attributes are: The default attributes are:
@ -542,7 +542,7 @@ class FieldConverter(osv.AbstractModel):
record._model._all_columns[field_name].column, record._model._all_columns[field_name].column,
options, context=context) options, context=context)
if options.get('html-escape', True): if options.get('html-escape', True):
content = werkzeug.utils.escape(content) content = escape(content)
elif hasattr(content, '__html__'): elif hasattr(content, '__html__'):
content = content.__html__() content = content.__html__()
except Exception: except Exception:
@ -553,7 +553,7 @@ class FieldConverter(osv.AbstractModel):
if context and context.get('inherit_branding'): if context and context.get('inherit_branding'):
# add branding attributes # add branding attributes
g_att += ''.join( g_att += ''.join(
' %s="%s"' % (name, werkzeug.utils.escape(value)) ' %s="%s"' % (name, escape(value))
for name, value in self.attributes( for name, value in self.attributes(
cr, uid, field_name, record, options, cr, uid, field_name, record, options,
source_element, g_att, t_att, qweb_context) source_element, g_att, t_att, qweb_context)
@ -875,7 +875,7 @@ class Contact(orm.AbstractModel):
val = { val = {
'name': value.split("\n")[0], 'name': value.split("\n")[0],
'address': werkzeug.utils.escape("\n".join(value.split("\n")[1:])), 'address': escape("\n".join(value.split("\n")[1:])),
'phone': field_browse.phone, 'phone': field_browse.phone,
'mobile': field_browse.mobile, 'mobile': field_browse.mobile,
'fax': field_browse.fax, 'fax': field_browse.fax,
@ -919,7 +919,7 @@ class QwebWidget(osv.AbstractModel):
return self.pool['ir.qweb'].eval_str(inner, qwebcontext) return self.pool['ir.qweb'].eval_str(inner, qwebcontext)
def format(self, inner, options, qwebcontext): def format(self, inner, options, qwebcontext):
return werkzeug.utils.escape(self._format(inner, options, qwebcontext)) return escape(self._format(inner, options, qwebcontext))
class QwebWidgetMonetary(osv.AbstractModel): class QwebWidgetMonetary(osv.AbstractModel):
_name = 'ir.qweb.widget.monetary' _name = 'ir.qweb.widget.monetary'
@ -979,7 +979,7 @@ def nl2br(string, options=None):
if options is None: options = {} if options is None: options = {}
if options.get('html-escape', True): if options.get('html-escape', True):
string = werkzeug.utils.escape(string) string = escape(string)
return HTMLSafe(string.replace('\n', '<br>\n')) return HTMLSafe(string.replace('\n', '<br>\n'))
def get_field_type(column, options): def get_field_type(column, options):

View File

@ -4,9 +4,8 @@ import os
import xml.dom.minidom import xml.dom.minidom
import datetime import datetime
from werkzeug.utils import escape as e
from openerp.tests import common from openerp.tests import common
from openerp.tools import html_escape as e
from openerp.addons.base.ir import ir_qweb from openerp.addons.base.ir import ir_qweb
directory = os.path.dirname(__file__) directory = os.path.dirname(__file__)

View File

@ -1267,7 +1267,7 @@ class function(_column):
if values and not multi and name in values[0]: if values and not multi and name in values[0]:
result = {v['id']: v[name] for v in values} result = {v['id']: v[name] for v in values}
elif values and multi and all(n in values[0] for n in name): elif values and multi and all(n in values[0] for n in name):
result = {v['id']: dict({n: v[n]} for n in name) for v in values} result = {v['id']: dict((n, v[n]) for n in name) for v in values}
else: else:
result = self._fnct(obj, cr, uid, ids, name, self._arg, context) result = self._fnct(obj, cr, uid, ids, name, self._arg, context)
if multi: if multi:

View File

@ -35,6 +35,7 @@ import socket
import sys import sys
import threading import threading
import time import time
import werkzeug.utils
import zipfile import zipfile
from collections import defaultdict, Mapping from collections import defaultdict, Mapping
from datetime import datetime from datetime import datetime
@ -51,6 +52,7 @@ except ImportError:
from config import config from config import config
from cache import * from cache import *
from .parse_version import parse_version
import openerp import openerp
# get_encodings, ustr and exception_to_unicode were originally from tools.misc. # get_encodings, ustr and exception_to_unicode were originally from tools.misc.
@ -1217,4 +1219,12 @@ def ignore(*exc):
except exc: except exc:
pass pass
# Avoid DeprecationWarning while still remaining compatible with werkzeug pre-0.9
if parse_version(getattr(werkzeug, '__version__', '0.0')) < parse_version('0.9.0'):
def html_escape(text):
return werkzeug.utils.escape(text, quote=True)
else:
def html_escape(text):
return werkzeug.utils.escape(text)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: