[MERGE] Sync with trunk
bzr revid: tde@openerp.com-20130910151742-rgmc2jwx6zyg38lp bzr revid: tde@openerp.com-20130912073916-1ph4x7cw6oovdafl bzr revid: tde@openerp.com-20130916092207-5rqco7ua9tbd1cvh
This commit is contained in:
commit
8583ced4cc
|
@ -37,7 +37,6 @@ There are two types of views:
|
||||||
|
|
||||||
.. note:: Since OpenERP 4.1, form views can also contain graphs.
|
.. note:: Since OpenERP 4.1, form views can also contain graphs.
|
||||||
|
|
||||||
|
|
||||||
Form views
|
Form views
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
@ -388,6 +387,33 @@ The easiest method to compute real statistics on objects is:
|
||||||
You can get en example in all modules of the form: report\_.... Example: report_crm.
|
You can get en example in all modules of the form: report\_.... Example: report_crm.
|
||||||
|
|
||||||
|
|
||||||
|
Controlling view actions
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
When defining a view, the following attributes can be added on the
|
||||||
|
opening element of the view (i.e. ``<form>``, ``<tree>``...)
|
||||||
|
|
||||||
|
``create``
|
||||||
|
set to ``false`` to hide the link / button which allows to create a new
|
||||||
|
record.
|
||||||
|
|
||||||
|
``delete``
|
||||||
|
set to ``false`` to hide the link / button which allows to remove a
|
||||||
|
record.
|
||||||
|
|
||||||
|
``edit``
|
||||||
|
set to ``false`` to hide the link / button which allows to
|
||||||
|
edit a record.
|
||||||
|
|
||||||
|
|
||||||
|
These attributes are available on form, tree, kanban and gantt
|
||||||
|
views. They are normally automatically set from the access rights of
|
||||||
|
the users, but can be forced globally in the view definition. A
|
||||||
|
possible use case for these attributes is to define an inner tree view
|
||||||
|
for a one2many relation inside a form view, in which the user cannot
|
||||||
|
add or remove related records, but only edit the existing ones (which
|
||||||
|
are presumably created through another way, such as a wizard).
|
||||||
|
|
||||||
|
|
||||||
Calendar Views
|
Calendar Views
|
||||||
--------------
|
--------------
|
||||||
|
@ -680,6 +706,7 @@ toolbar
|
||||||
its descendants will be displayed in the main tree. The value is ignored
|
its descendants will be displayed in the main tree. The value is ignored
|
||||||
for flat lists.
|
for flat lists.
|
||||||
|
|
||||||
|
|
||||||
Grouping Elements
|
Grouping Elements
|
||||||
+++++++++++++++++
|
+++++++++++++++++
|
||||||
|
|
||||||
|
@ -1351,12 +1378,22 @@ When you add a one2many field in a form view, you do something like this :
|
||||||
|
|
||||||
If you want to specify the views to use, you can add a *context* attribute, and
|
If you want to specify the views to use, you can add a *context* attribute, and
|
||||||
specify a view id for each type of view supported, exactly like the action's
|
specify a view id for each type of view supported, exactly like the action's
|
||||||
*view_id* attribute:
|
*view_id* attribute, except that the provided view id must always be
|
||||||
|
fully-qualified with the module name, even if it belongs to the same module:
|
||||||
|
|
||||||
.. code-block:: xml
|
.. code-block:: xml
|
||||||
|
|
||||||
<field name="order_line" colspan="4" nolabel="1"
|
<field name="order_line" colspan="4" nolabel="1"
|
||||||
context="{'form_view_ref' : 'module.view_id', 'tree_view_ref' : 'model.view_id'}"/>
|
context="{'form_view_ref': 'module.view_id',
|
||||||
|
'tree_view_ref': 'module.view_id'}"/>
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
You *have to* put the module name in the view_id, because this
|
||||||
|
is evaluated when the view is displayed, and not when the XML file
|
||||||
|
is parsed, so the module name information is not available. Failing
|
||||||
|
to do so will result in the default view being selected (see
|
||||||
|
below).
|
||||||
|
|
||||||
If you don't specify the views, OpenERP will choose one in this order :
|
If you don't specify the views, OpenERP will choose one in this order :
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,10 +49,10 @@ class res_config_module_installation_mixin(object):
|
||||||
to_install_missing_names.append(name)
|
to_install_missing_names.append(name)
|
||||||
elif module.state == 'uninstalled':
|
elif module.state == 'uninstalled':
|
||||||
to_install_ids.append(module.id)
|
to_install_ids.append(module.id)
|
||||||
|
result = None
|
||||||
if to_install_ids:
|
if to_install_ids:
|
||||||
ir_module.button_immediate_install(cr, uid, to_install_ids, context=context)
|
result = ir_module.button_immediate_install(cr, uid, to_install_ids, context=context)
|
||||||
|
#FIXME: if result is not none, the corresponding todo will be skipped because it was just marked done
|
||||||
if to_install_missing_names:
|
if to_install_missing_names:
|
||||||
return {
|
return {
|
||||||
'type': 'ir.actions.client',
|
'type': 'ir.actions.client',
|
||||||
|
@ -60,7 +60,7 @@ class res_config_module_installation_mixin(object):
|
||||||
'params': {'modules': to_install_missing_names},
|
'params': {'modules': to_install_missing_names},
|
||||||
}
|
}
|
||||||
|
|
||||||
return None
|
return result
|
||||||
|
|
||||||
class res_config_configurable(osv.osv_memory):
|
class res_config_configurable(osv.osv_memory):
|
||||||
''' Base classes for new-style configuration items
|
''' Base classes for new-style configuration items
|
||||||
|
|
|
@ -481,7 +481,11 @@ class res_partner(osv.osv, format_address):
|
||||||
if partner.child_ids:
|
if partner.child_ids:
|
||||||
# 2a. Commercial Fields: sync if commercial entity
|
# 2a. Commercial Fields: sync if commercial entity
|
||||||
if partner.commercial_partner_id == partner:
|
if partner.commercial_partner_id == partner:
|
||||||
self._commercial_sync_to_children(cr, uid, partner, context=context)
|
commercial_fields = self._commercial_fields(cr, uid,
|
||||||
|
context=context)
|
||||||
|
if any(field in update_values for field in commercial_fields):
|
||||||
|
self._commercial_sync_to_children(cr, uid, partner,
|
||||||
|
context=context)
|
||||||
# 2b. Address fields: sync if address changed
|
# 2b. Address fields: sync if address changed
|
||||||
address_fields = self._address_fields(cr, uid, context=context)
|
address_fields = self._address_fields(cr, uid, context=context)
|
||||||
if any(field in update_values for field in address_fields):
|
if any(field in update_values for field in address_fields):
|
||||||
|
@ -504,6 +508,16 @@ class res_partner(osv.osv, format_address):
|
||||||
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]
|
||||||
|
#res.partner must only allow to set the company_id of a partner if it
|
||||||
|
#is the same as the company of all users that inherit from this partner
|
||||||
|
#(this is to allow the code from res_users to write to the partner!) or
|
||||||
|
#if setting the company_id to False (this is compatible with any user company)
|
||||||
|
if vals.get('company_id'):
|
||||||
|
for partner in self.browse(cr, uid, ids, context=context):
|
||||||
|
if partner.user_ids:
|
||||||
|
user_companies = set([user.company_id.id for user in partner.user_ids])
|
||||||
|
if len(user_companies) > 1 or vals['company_id'] not in user_companies:
|
||||||
|
raise osv.except_osv(_("Warning"),_("You can not change the company as the partner/user has multiple user linked with different companies."))
|
||||||
result = super(res_partner,self).write(cr, uid, ids, vals, context=context)
|
result = super(res_partner,self).write(cr, uid, ids, vals, context=context)
|
||||||
for partner in self.browse(cr, uid, ids, context=context):
|
for partner in self.browse(cr, uid, ids, context=context):
|
||||||
self._fields_sync(cr, uid, partner, vals, context)
|
self._fields_sync(cr, uid, partner, vals, context)
|
||||||
|
@ -604,14 +618,15 @@ class res_partner(osv.osv, format_address):
|
||||||
if operator in ('=ilike', '=like'):
|
if operator in ('=ilike', '=like'):
|
||||||
operator = operator[1:]
|
operator = operator[1:]
|
||||||
query_args = {'name': search_name}
|
query_args = {'name': search_name}
|
||||||
limit_str = ''
|
query = ('''SELECT id FROM res_partner
|
||||||
|
WHERE email ''' + operator + ''' %(name)s
|
||||||
|
OR display_name ''' + operator + ''' %(name)s
|
||||||
|
ORDER BY display_name
|
||||||
|
''')
|
||||||
if limit:
|
if limit:
|
||||||
limit_str = ' limit %(limit)s'
|
query += ' limit %(limit)s'
|
||||||
query_args['limit'] = limit
|
query_args['limit'] = limit
|
||||||
cr.execute('''SELECT partner.id FROM res_partner partner
|
cr.execute(query, query_args)
|
||||||
LEFT JOIN res_partner company ON partner.parent_id = company.id
|
|
||||||
WHERE partner.email ''' + operator +''' %(name)s OR
|
|
||||||
partner.display_name ''' + operator + ' %(name)s ' + limit_str, query_args)
|
|
||||||
ids = map(lambda x: x[0], cr.fetchall())
|
ids = map(lambda x: x[0], cr.fetchall())
|
||||||
ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, context=context)
|
ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, context=context)
|
||||||
if ids:
|
if ids:
|
||||||
|
|
|
@ -283,6 +283,13 @@ class res_users(osv.osv):
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def create(self, cr, uid, vals, context=None):
|
||||||
|
user_id = super(res_users, self).create(cr, uid, vals, context=context)
|
||||||
|
user = self.browse(cr, uid, user_id, context=context)
|
||||||
|
if user.partner_id.company_id:
|
||||||
|
user.partner_id.write({'company_id': user.company_id.id})
|
||||||
|
return user_id
|
||||||
|
|
||||||
def write(self, cr, uid, ids, values, context=None):
|
def write(self, cr, uid, ids, values, context=None):
|
||||||
if not hasattr(ids, '__iter__'):
|
if not hasattr(ids, '__iter__'):
|
||||||
ids = [ids]
|
ids = [ids]
|
||||||
|
@ -297,7 +304,11 @@ class res_users(osv.osv):
|
||||||
uid = 1 # safe fields only, so we write as super-user to bypass access rights
|
uid = 1 # safe fields only, so we write as super-user to bypass access rights
|
||||||
|
|
||||||
res = super(res_users, self).write(cr, uid, ids, values, context=context)
|
res = super(res_users, self).write(cr, uid, ids, values, context=context)
|
||||||
|
if 'company_id' in values:
|
||||||
|
for user in self.browse(cr, uid, ids, context=context):
|
||||||
|
# if partner is global we keep it that way
|
||||||
|
if user.partner_id.company_id and user.partner_id.company_id.id != values['company_id']:
|
||||||
|
user.partner_id.write({'company_id': user.company_id.id})
|
||||||
# clear caches linked to the users
|
# clear caches linked to the users
|
||||||
self.pool['ir.model.access'].call_cache_clearing_methods(cr)
|
self.pool['ir.model.access'].call_cache_clearing_methods(cr)
|
||||||
clear = partial(self.pool['ir.rule'].clear_cache, cr)
|
clear = partial(self.pool['ir.rule'].clear_cache, cr)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
"access_ir_model_relation","ir_model_relation","model_ir_model_relation",,1,0,0,0
|
"access_ir_model_relation","ir_model_relation","model_ir_model_relation",,1,0,0,0
|
||||||
"access_ir_model_access_all","ir_model_access_all","model_ir_model_access",,1,0,0,0
|
"access_ir_model_access_all","ir_model_access_all","model_ir_model_access",,1,0,0,0
|
||||||
"access_ir_model_data_all","ir_model_data all","model_ir_model_data",,1,0,0,0
|
"access_ir_model_data_all","ir_model_data all","model_ir_model_data",,1,0,0,0
|
||||||
|
"access_ir_model_data_user","ir_model_data user","model_ir_model_data",base.group_user,1,0,1,0
|
||||||
"access_ir_model_fields_all","ir_model_fields all","model_ir_model_fields",,1,0,0,0
|
"access_ir_model_fields_all","ir_model_fields all","model_ir_model_fields",,1,0,0,0
|
||||||
"access_ir_module_category_group_user","ir_module_category group_user","model_ir_module_category",,1,0,0,0
|
"access_ir_module_category_group_user","ir_module_category group_user","model_ir_module_category",,1,0,0,0
|
||||||
"access_ir_module_module_group_user","ir_module_module group_user","model_ir_module_module","group_system",1,1,1,1
|
"access_ir_module_module_group_user","ir_module_module group_user","model_ir_module_module","group_system",1,1,1,1
|
||||||
|
@ -110,9 +111,7 @@
|
||||||
"access_res_bank_user","res_bank user","model_res_bank","group_user",1,0,0,0
|
"access_res_bank_user","res_bank user","model_res_bank","group_user",1,0,0,0
|
||||||
"access_multi_company_default user","multi_company_default all","model_multi_company_default",,1,0,0,0
|
"access_multi_company_default user","multi_company_default all","model_multi_company_default",,1,0,0,0
|
||||||
"access_multi_company_default manager","multi_company_default Manager","model_multi_company_default","group_erp_manager",1,1,1,1
|
"access_multi_company_default manager","multi_company_default Manager","model_multi_company_default","group_erp_manager",1,1,1,1
|
||||||
"access_ir_filter all","ir_filters all","model_ir_filters",,1,0,0,0
|
"access_ir_filter all","ir_filters all","model_ir_filters",,1,1,1,1
|
||||||
"access_ir_filter employee","ir_filters employee","model_ir_filters","group_user",1,1,1,1
|
|
||||||
"access_ir_filters","ir_filters_all","model_ir_filters",,1,1,1,1
|
|
||||||
"access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0
|
"access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0
|
||||||
"access_ir_mail_server","ir_mail_server","model_ir_mail_server","group_system",1,1,1,1
|
"access_ir_mail_server","ir_mail_server","model_ir_mail_server","group_system",1,1,1,1
|
||||||
"access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0
|
"access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0
|
||||||
|
|
|
|
@ -56,19 +56,6 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||||
:param skip_modules: optional list of module names (packages) which have previously been loaded and can be skipped
|
:param skip_modules: optional list of module names (packages) which have previously been loaded and can be skipped
|
||||||
:return: list of modules that were installed or updated
|
:return: list of modules that were installed or updated
|
||||||
"""
|
"""
|
||||||
def process_sql_file(cr, fp):
|
|
||||||
queries = fp.read().split(';')
|
|
||||||
for query in queries:
|
|
||||||
new_query = ' '.join(query.split())
|
|
||||||
if new_query:
|
|
||||||
cr.execute(new_query)
|
|
||||||
|
|
||||||
load_init_xml = lambda *args: _load_data(cr, *args, kind='init_xml')
|
|
||||||
load_update_xml = lambda *args: _load_data(cr, *args, kind='update_xml')
|
|
||||||
load_demo_xml = lambda *args: _load_data(cr, *args, kind='demo_xml')
|
|
||||||
load_data = lambda *args: _load_data(cr, *args, kind='data')
|
|
||||||
load_demo = lambda *args: _load_data(cr, *args, kind='demo')
|
|
||||||
|
|
||||||
def load_test(module_name, idref, mode):
|
def load_test(module_name, idref, mode):
|
||||||
cr.commit()
|
cr.commit()
|
||||||
try:
|
try:
|
||||||
|
@ -86,6 +73,28 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||||
else:
|
else:
|
||||||
cr.rollback()
|
cr.rollback()
|
||||||
|
|
||||||
|
def _get_files_of_kind(kind):
|
||||||
|
if kind == 'demo':
|
||||||
|
kind = ['demo_xml', 'demo']
|
||||||
|
elif kind == 'data':
|
||||||
|
kind = ['init_xml', 'update_xml', 'data']
|
||||||
|
if isinstance(kind, str):
|
||||||
|
kind = [kind]
|
||||||
|
files = []
|
||||||
|
for k in kind:
|
||||||
|
for f in package.data[k]:
|
||||||
|
files.append(f)
|
||||||
|
if k.endswith('_xml') and not (k == 'init_xml' and not f.endswith('.xml')):
|
||||||
|
# init_xml, update_xml and demo_xml are deprecated except
|
||||||
|
# for the case of init_xml with yaml, csv and sql files as
|
||||||
|
# we can't specify noupdate for those file.
|
||||||
|
correct_key = 'demo' if k.count('demo') else 'data'
|
||||||
|
_logger.warning(
|
||||||
|
"module %s: key '%s' is deprecated in favor of '%s' for file '%s'.",
|
||||||
|
package.name, k, correct_key, f
|
||||||
|
)
|
||||||
|
return files
|
||||||
|
|
||||||
def _load_data(cr, module_name, idref, mode, kind):
|
def _load_data(cr, module_name, idref, mode, kind):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -95,32 +104,12 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||||
init mode.
|
init mode.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for filename in package.data[kind]:
|
for filename in _get_files_of_kind(kind):
|
||||||
_logger.info("module %s: loading %s", module_name, filename)
|
_logger.info("module %s: loading %s", module_name, filename)
|
||||||
_, ext = os.path.splitext(filename)
|
|
||||||
pathname = os.path.join(module_name, filename)
|
|
||||||
fp = tools.file_open(pathname)
|
|
||||||
noupdate = False
|
noupdate = False
|
||||||
if kind in ('demo', 'demo_xml'):
|
if kind in ('demo', 'demo_xml') or (filename.endswith('.csv') and kind in ('init', 'init_xml')):
|
||||||
noupdate = True
|
noupdate = True
|
||||||
try:
|
tools.convert_file(cr, module_name, filename, idref, mode, noupdate, kind, report)
|
||||||
ext = ext.lower()
|
|
||||||
if ext == '.csv':
|
|
||||||
if kind in ('init', 'init_xml'):
|
|
||||||
noupdate = True
|
|
||||||
tools.convert_csv_import(cr, module_name, pathname, fp.read(), idref, mode, noupdate)
|
|
||||||
elif ext == '.sql':
|
|
||||||
process_sql_file(cr, fp)
|
|
||||||
elif ext == '.yml':
|
|
||||||
tools.convert_yaml_import(cr, module_name, fp, kind, idref, mode, noupdate, report)
|
|
||||||
elif ext == '.xml':
|
|
||||||
tools.convert_xml_import(cr, module_name, fp, idref, mode, noupdate, report)
|
|
||||||
elif ext == '.js':
|
|
||||||
pass # .js files are valid but ignored here.
|
|
||||||
else:
|
|
||||||
_logger.warning("Can't load unknown file type %s.", filename)
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
if status is None:
|
if status is None:
|
||||||
status = {}
|
status = {}
|
||||||
|
@ -176,13 +165,10 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
|
||||||
if package.state=='to upgrade':
|
if package.state=='to upgrade':
|
||||||
# upgrading the module information
|
# upgrading the module information
|
||||||
modobj.write(cr, SUPERUSER_ID, [module_id], modobj.get_values_from_terp(package.data))
|
modobj.write(cr, SUPERUSER_ID, [module_id], modobj.get_values_from_terp(package.data))
|
||||||
load_init_xml(module_name, idref, mode)
|
_load_data(cr, module_name, idref, mode, kind='data')
|
||||||
load_update_xml(module_name, idref, mode)
|
|
||||||
load_data(module_name, idref, mode)
|
|
||||||
if hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed'):
|
if hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed'):
|
||||||
status['progress'] = (index + 0.75) / len(graph)
|
status['progress'] = (index + 0.75) / len(graph)
|
||||||
load_demo_xml(module_name, idref, mode)
|
_load_data(cr, module_name, idref, mode, kind='demo')
|
||||||
load_demo(module_name, idref, mode)
|
|
||||||
cr.execute('update ir_module_module set demo=%s where id=%s', (True, module_id))
|
cr.execute('update ir_module_module set demo=%s where id=%s', (True, module_id))
|
||||||
|
|
||||||
# launch tests only in demo mode, as most tests will depend
|
# launch tests only in demo mode, as most tests will depend
|
||||||
|
@ -329,13 +315,21 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||||
# they are part of the "currently installed" modules. They will
|
# they are part of the "currently installed" modules. They will
|
||||||
# be dropped in STEP 6 later, before restarting the loading
|
# be dropped in STEP 6 later, before restarting the loading
|
||||||
# process.
|
# process.
|
||||||
states_to_load = ['installed', 'to upgrade', 'to remove']
|
# IMPORTANT 2: We have to loop here until all relevant modules have been
|
||||||
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules, update_module)
|
# processed, because in some rare cases the dependencies have
|
||||||
processed_modules.extend(processed)
|
# changed, and modules that depend on an uninstalled module
|
||||||
if update_module:
|
# will not be processed on the first pass.
|
||||||
states_to_load = ['to install']
|
# It's especially useful for migrations.
|
||||||
processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules, update_module)
|
previously_processed = -1
|
||||||
processed_modules.extend(processed)
|
while previously_processed < len(processed_modules):
|
||||||
|
previously_processed = len(processed_modules)
|
||||||
|
processed_modules += load_marked_modules(cr, graph,
|
||||||
|
['installed', 'to upgrade', 'to remove'],
|
||||||
|
force, status, report, loaded_modules, update_module)
|
||||||
|
if update_module:
|
||||||
|
processed_modules += load_marked_modules(cr, graph,
|
||||||
|
['to install'], force, status, report,
|
||||||
|
loaded_modules, update_module)
|
||||||
|
|
||||||
# load custom models
|
# load custom models
|
||||||
cr.execute('select model from ir_model where state=%s', ('manual',))
|
cr.execute('select model from ir_model where state=%s', ('manual',))
|
||||||
|
|
|
@ -33,6 +33,7 @@ import time
|
||||||
import openerp
|
import openerp
|
||||||
import openerp.release
|
import openerp.release
|
||||||
import openerp.workflow
|
import openerp.workflow
|
||||||
|
from yaml_import import convert_yaml_import
|
||||||
|
|
||||||
import assertion_report
|
import assertion_report
|
||||||
|
|
||||||
|
@ -877,6 +878,33 @@ form: module.record_id""" % (xml_id,)
|
||||||
'url': self._tag_url
|
'url': self._tag_url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def convert_file(cr, module, filename, idref, mode='update', noupdate=False, kind=None, report=None):
|
||||||
|
pathname = os.path.join(module, filename)
|
||||||
|
fp = misc.file_open(pathname)
|
||||||
|
ext = os.path.splitext(filename)[1].lower()
|
||||||
|
try:
|
||||||
|
if ext == '.csv':
|
||||||
|
convert_csv_import(cr, module, pathname, fp.read(), idref, mode, noupdate)
|
||||||
|
elif ext == '.sql':
|
||||||
|
convert_sql_import(cr, fp)
|
||||||
|
elif ext == '.yml':
|
||||||
|
convert_yaml_import(cr, module, fp, kind, idref, mode, noupdate, report)
|
||||||
|
elif ext == '.xml':
|
||||||
|
convert_xml_import(cr, module, fp, idref, mode, noupdate, report)
|
||||||
|
elif ext == '.js':
|
||||||
|
pass # .js files are valid but ignored here.
|
||||||
|
else:
|
||||||
|
_logger.warning("Can't load unknown file type %s.", filename)
|
||||||
|
finally:
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
def convert_sql_import(cr, fp):
|
||||||
|
queries = fp.read().split(';')
|
||||||
|
for query in queries:
|
||||||
|
new_query = ' '.join(query.split())
|
||||||
|
if new_query:
|
||||||
|
cr.execute(new_query)
|
||||||
|
|
||||||
def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init',
|
def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init',
|
||||||
noupdate=False):
|
noupdate=False):
|
||||||
'''Import csv file :
|
'''Import csv file :
|
||||||
|
|
|
@ -43,6 +43,9 @@ _logger = logging.getLogger(__name__)
|
||||||
tags_to_kill = ["script", "head", "meta", "title", "link", "style", "frame", "iframe", "base", "object", "embed"]
|
tags_to_kill = ["script", "head", "meta", "title", "link", "style", "frame", "iframe", "base", "object", "embed"]
|
||||||
tags_to_remove = ['html', 'body', 'font']
|
tags_to_remove = ['html', 'body', 'font']
|
||||||
|
|
||||||
|
# allow new semantic HTML5 tags
|
||||||
|
allowed_tags = clean.defs.tags | frozenset('article section header footer hgroup nav aside figure'.split())
|
||||||
|
safe_attrs = clean.defs.safe_attrs | frozenset(['style'])
|
||||||
|
|
||||||
def html_sanitize(src, silent=True):
|
def html_sanitize(src, silent=True):
|
||||||
if not src:
|
if not src:
|
||||||
|
@ -59,6 +62,8 @@ def html_sanitize(src, silent=True):
|
||||||
'page_structure': True,
|
'page_structure': True,
|
||||||
'style': False, # do not remove style attributes
|
'style': False, # do not remove style attributes
|
||||||
'forms': True, # remove form tags
|
'forms': True, # remove form tags
|
||||||
|
'remove_unknown_tags': False,
|
||||||
|
'allow_tags': allowed_tags,
|
||||||
}
|
}
|
||||||
if etree.LXML_VERSION >= (2, 3, 1):
|
if etree.LXML_VERSION >= (2, 3, 1):
|
||||||
# kill_tags attribute has been added in version 2.3.1
|
# kill_tags attribute has been added in version 2.3.1
|
||||||
|
@ -72,7 +77,7 @@ def html_sanitize(src, silent=True):
|
||||||
if etree.LXML_VERSION >= (3, 1, 0):
|
if etree.LXML_VERSION >= (3, 1, 0):
|
||||||
kwargs.update({
|
kwargs.update({
|
||||||
'safe_attrs_only': True,
|
'safe_attrs_only': True,
|
||||||
'safe_attrs': clean.defs.safe_attrs | set(['style']),
|
'safe_attrs': safe_attrs,
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
# lxml < 3.1.0 does not allow to specify safe_attrs. We keep all attributes in order to keep "style"
|
# lxml < 3.1.0 does not allow to specify safe_attrs. We keep all attributes in order to keep "style"
|
||||||
|
|
Loading…
Reference in New Issue