[MERGE] Forward-port saas-11 up to eb6b256f99
This commit is contained in:
@@ -44,6 +44,10 @@ class ir_module_module(osv.osv):
|
||||
|
||||
for kind in ['data', 'init_xml', 'update_xml']:
|
||||
for filename in terp[kind]:
|
||||
ext = os.path.splitext(filename)[1].lower()
|
||||
if ext not in ('.xml', '.csv', '.sql'):
|
||||
_logger.info("module %s: skip unsupported file %s", module, filename)
|
||||
continue
|
||||
_logger.info("module %s: loading %s", module, filename)
|
||||
noupdate = False
|
||||
if filename.endswith('.csv') and kind in ('init', 'init_xml'):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import controllers
|
||||
import models
|
||||
import report
|
||||
import wizard
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*
|
||||
import main
|
||||
@@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.addons.mail.controllers.main import MailController
|
||||
from openerp import http
|
||||
|
||||
|
||||
class CrmController(http.Controller):
|
||||
|
||||
@http.route('/lead/case_mark_won', type='http', auth='user', methods=['GET'])
|
||||
def crm_lead_case_mark_won(self, res_id, token):
|
||||
comparison, record, redirect = MailController._check_token_and_record_or_redirect('crm.lead', int(res_id), token)
|
||||
if comparison and record:
|
||||
try:
|
||||
record.case_mark_won()
|
||||
except Exception:
|
||||
return MailController._redirect_to_messaging()
|
||||
return redirect
|
||||
|
||||
@http.route('/lead/case_mark_lost', type='http', auth='user', methods=['GET'])
|
||||
def crm_lead_case_mark_lost(self, res_id, token):
|
||||
comparison, record, redirect = MailController._check_token_and_record_or_redirect('crm.lead', int(res_id), token)
|
||||
if comparison and record:
|
||||
try:
|
||||
record.case_mark_lost()
|
||||
except Exception:
|
||||
return MailController._redirect_to_messaging()
|
||||
return redirect
|
||||
|
||||
@http.route('/lead/convert', type='http', auth='user', methods=['GET'])
|
||||
def crm_lead_convert(self, res_id, token):
|
||||
comparison, record, redirect = MailController._check_token_and_record_or_redirect('crm.lead', int(res_id), token)
|
||||
if comparison and record:
|
||||
try:
|
||||
record.convert_opportunity(record.partner_id.id)
|
||||
except Exception:
|
||||
return MailController._redirect_to_messaging()
|
||||
return redirect
|
||||
@@ -1062,9 +1062,12 @@ class Lead(FormatAddress, models.Model):
|
||||
result = super(Lead, self)._notification_get_recipient_groups(message, recipients)
|
||||
|
||||
lead = self[0]
|
||||
won_action = self._notification_link_helper('method', method='action_set_won')
|
||||
lost_action = self._notification_link_helper('method', method='action_set_lost')
|
||||
convert_action = self._notification_link_helper('method', method='convert_opportunity', partner_id=lead.partner_id.id)
|
||||
won_action = self._notification_link_helper('controller', controller='/lead/case_mark_won')
|
||||
lost_action = self._notification_link_helper('controller', controller='/lead/case_mark_lost')
|
||||
convert_action = self._notification_link_helper('controller', controller='/lead/convert')
|
||||
|
||||
|
||||
|
||||
|
||||
if lead.type == 'lead':
|
||||
result['group_sale_salesman'] = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import controllers
|
||||
import models
|
||||
import report
|
||||
import wizard
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*
|
||||
import main
|
||||
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.addons.mail.controllers.main import MailController
|
||||
from openerp import http
|
||||
|
||||
|
||||
class HrHolidaysController(http.Controller):
|
||||
|
||||
@http.route('/hr_holidays/validate', type='http', auth='user', methods=['GET'])
|
||||
def hr_holidays_validate(self, res_id, token):
|
||||
comparison, record, redirect = MailController._check_token_and_record_or_redirect('hr.holidays', int(res_id), token)
|
||||
if comparison and record:
|
||||
try:
|
||||
record.signal_workflow('validate')
|
||||
except Exception:
|
||||
return MailController._redirect_to_messaging()
|
||||
return redirect
|
||||
|
||||
@http.route('/hr_holidays/refuse', type='http', auth='user', methods=['GET'])
|
||||
def hr_holidays_refuse(self, res_id, token):
|
||||
comparison, record, redirect = MailController._check_token_and_record_or_redirect('hr.holidays', int(res_id), token)
|
||||
if comparison and record:
|
||||
try:
|
||||
record.signal_workflow('refuse')
|
||||
except Exception:
|
||||
return MailController._redirect_to_messaging()
|
||||
return redirect
|
||||
@@ -535,8 +535,10 @@ class Holidays(models.Model):
|
||||
def _notification_get_recipient_groups(self, message, recipients):
|
||||
result = super(Holidays, self)._notification_get_recipient_groups(message, recipients)
|
||||
|
||||
app_action = '/mail/workflow?%s' % url_encode({'model': self._name, 'res_id': self.id, 'signal': 'validate'})
|
||||
ref_action = '/mail/workflow?%s' % url_encode({'model': self._name, 'res_id': self.id, 'signal': 'refuse'})
|
||||
app_action = self._notification_link_helper('controller', controller='/hr_holidays/validate')
|
||||
ref_action = self._notification_link_helper('controller', controller='/hr_holidays/refuse')
|
||||
|
||||
|
||||
|
||||
actions = []
|
||||
if self.state == 'confirm':
|
||||
|
||||
+105
-100
@@ -1,5 +1,6 @@
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
from operator import itemgetter
|
||||
import psycopg2
|
||||
import werkzeug
|
||||
@@ -8,20 +9,90 @@ from werkzeug import url_encode
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp import http
|
||||
from openerp import _
|
||||
from openerp.exceptions import AccessError
|
||||
from openerp.http import request
|
||||
from openerp.tools import consteq
|
||||
|
||||
from openerp.addons.web.controllers.main import binary_content
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MailController(http.Controller):
|
||||
_cp_path = '/mail'
|
||||
|
||||
def _redirect_to_messaging(self):
|
||||
@classmethod
|
||||
def _redirect_to_messaging(cls):
|
||||
messaging_action = request.env['mail.thread']._get_inbox_action_xml_id()
|
||||
url = '/web#%s' % url_encode({'action': messaging_action})
|
||||
return werkzeug.utils.redirect(url)
|
||||
|
||||
@classmethod
|
||||
def _check_token(cls, token):
|
||||
base_link = request.httprequest.path
|
||||
params = dict(request.params)
|
||||
params.pop('token', '')
|
||||
valid_token = request.env['mail.thread']._generate_notification_token(base_link, params)
|
||||
return consteq(valid_token, str(token))
|
||||
|
||||
@classmethod
|
||||
def _check_token_and_record_or_redirect(cls, model, res_id, token):
|
||||
comparison = cls._check_token(token)
|
||||
if not comparison:
|
||||
_logger.warning(_('Invalid token in route %s') % request.httprequest.url)
|
||||
return comparison, None, cls._redirect_to_messaging()
|
||||
try:
|
||||
record = request.env[model].browse(res_id).exists()
|
||||
except Exception:
|
||||
record = None
|
||||
redirect = cls._redirect_to_messaging()
|
||||
else:
|
||||
redirect = cls._redirect_to_record(model, res_id)
|
||||
return comparison, record, redirect
|
||||
|
||||
@classmethod
|
||||
def _redirect_to_record(cls, model, res_id):
|
||||
uid = request.session.uid
|
||||
|
||||
# no model / res_id, meaning no possible record -> redirect to login
|
||||
if not model or not res_id or model not in request.env:
|
||||
return cls._redirect_to_messaging()
|
||||
|
||||
# find the access action using sudo to have the details about the access link
|
||||
RecordModel = request.env[model]
|
||||
record_sudo = RecordModel.sudo().browse(res_id).exists()
|
||||
if not record_sudo:
|
||||
# record does not seem to exist -> redirect to login
|
||||
return cls._redirect_to_messaging()
|
||||
record_action = record_sudo.get_access_action()
|
||||
|
||||
# the record has an URL redirection: use it directly
|
||||
if record_action['type'] == 'ir.actions.act_url':
|
||||
return werkzeug.utils.redirect(record_action['url'])
|
||||
# other choice: act_window (no support of anything else currently)
|
||||
elif not record_action['type'] == 'ir.actions.act_window':
|
||||
return cls._redirect_to_messaging()
|
||||
|
||||
# the record has a window redirection: check access rights
|
||||
if not RecordModel.sudo(uid).check_access_rights('read', raise_exception=False):
|
||||
return cls._redirect_to_messaging()
|
||||
try:
|
||||
record_sudo.sudo(uid).check_access_rule('read')
|
||||
except AccessError:
|
||||
return cls._redirect_to_messaging()
|
||||
|
||||
url_params = {
|
||||
'view_type': record_action['view_type'],
|
||||
'model': model,
|
||||
'id': res_id,
|
||||
'active_id': res_id,
|
||||
'view_id': record_sudo.get_formview_id(),
|
||||
'action': record_action.get('id'),
|
||||
}
|
||||
url = '/web?#%s' % url_encode(url_params)
|
||||
return werkzeug.utils.redirect(url)
|
||||
|
||||
@http.route('/mail/receive', type='json', auth='none')
|
||||
def receive(self, req):
|
||||
""" End-point to receive mail from an external SMTP server. """
|
||||
@@ -93,8 +164,6 @@ class MailController(http.Controller):
|
||||
- users without read access are redirected to the Messaging
|
||||
- not logged users are redirected to the login page
|
||||
"""
|
||||
uid = request.session.uid
|
||||
|
||||
if message_id:
|
||||
try:
|
||||
message = request.env['mail.message'].sudo().browse(int(message_id)).exists()
|
||||
@@ -108,112 +177,48 @@ class MailController(http.Controller):
|
||||
elif res_id and isinstance(res_id, basestring):
|
||||
res_id = int(res_id)
|
||||
|
||||
# no model / res_id, meaning no possible record -> redirect to login
|
||||
if not model or not res_id or model not in request.env:
|
||||
return self._redirect_to_messaging()
|
||||
return self._redirect_to_record(model, res_id)
|
||||
|
||||
# find the access action using sudo to have the details about the access link
|
||||
RecordModel = request.env[model].sudo(uid)
|
||||
record = RecordModel.browse(res_id).exists()
|
||||
if not record:
|
||||
# record does not seem to exist -> redirect to login
|
||||
return self._redirect_to_messaging()
|
||||
record_action = record.get_access_action()
|
||||
@http.route('/mail/follow', type='http', auth='user', methods=['GET'])
|
||||
def mail_action_follow(self, model, res_id, token=None):
|
||||
comparison, record, redirect = self._check_token_and_record_or_redirect(model, int(res_id), token)
|
||||
if comparison and record:
|
||||
try:
|
||||
record.sudo().message_subscribe_users()
|
||||
except Exception:
|
||||
return self._redirect_to_messaging()
|
||||
return redirect
|
||||
|
||||
# only URL redirections or window actions supported currently
|
||||
if not record_action['type'] in ('ir.actions.act_url', 'ir.actions.act_window'):
|
||||
return self._redirect_to_messaging()
|
||||
|
||||
# the record has an URL redirection: use it directly
|
||||
if record_action['type'] == 'ir.actions.act_url':
|
||||
return werkzeug.utils.redirect(record_action['url'])
|
||||
|
||||
# the record has a window redirection: check access rights
|
||||
if not RecordModel.check_access_rights('read', raise_exception=False):
|
||||
return self._redirect_to_messaging()
|
||||
try:
|
||||
record.check_access_rule('read')
|
||||
except AccessError:
|
||||
return self._redirect_to_messaging()
|
||||
|
||||
# at this point user can read the document so no issue with get_formview_id
|
||||
query = {}
|
||||
url_params = {
|
||||
'view_type': record_action['view_type'],
|
||||
'model': model,
|
||||
'id': res_id,
|
||||
'active_id': res_id,
|
||||
'view_id': record.get_formview_id(),
|
||||
'action': record_action.get('id'),
|
||||
}
|
||||
url = '/web?%s#%s' % (url_encode(query), url_encode(url_params))
|
||||
return werkzeug.utils.redirect(url)
|
||||
|
||||
@http.route('/mail/follow', type='http', auth='user')
|
||||
def mail_action_follow(self, model, res_id):
|
||||
if model not in request.env:
|
||||
return self._redirect_to_messaging()
|
||||
Model = request.env[model]
|
||||
try:
|
||||
Model.browse(res_id).message_subscribe_users()
|
||||
except:
|
||||
return self._redirect_to_messaging()
|
||||
return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
|
||||
|
||||
@http.route('/mail/unfollow', type='http', auth='user')
|
||||
def mail_action_unfollow(self, model, res_id):
|
||||
if model not in request.env:
|
||||
return self._redirect_to_messaging()
|
||||
Model = request.env[model]
|
||||
try:
|
||||
Model.browse(res_id).sudo().message_unsubscribe_users([request.uid])
|
||||
except:
|
||||
return self._redirect_to_messaging()
|
||||
return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
|
||||
@http.route('/mail/unfollow', type='http', auth='user', methods=['GET'])
|
||||
def mail_action_unfollow(self, model, res_id, token=None):
|
||||
comparison, record, redirect = self._check_token_and_record_or_redirect(model, int(res_id), token)
|
||||
if comparison and record:
|
||||
try:
|
||||
# TDE CHECKME: is sudo really necessary ?
|
||||
record.sudo().message_unsubscribe_users([request.uid])
|
||||
except Exception:
|
||||
return self._redirect_to_messaging()
|
||||
return redirect
|
||||
|
||||
@http.route('/mail/new', type='http', auth='user')
|
||||
def mail_action_new(self, model, res_id, **kwargs):
|
||||
def mail_action_new(self, model, res_id, action_id):
|
||||
if model not in request.env:
|
||||
return self._redirect_to_messaging()
|
||||
params = {'view_type': 'form', 'model': model}
|
||||
if kwargs.get('action_id'):
|
||||
params['action'] = kwargs['action_id']
|
||||
if action_id:
|
||||
# Probably something to do
|
||||
params['action'] = action_id
|
||||
return werkzeug.utils.redirect('/web?#%s' % url_encode(params))
|
||||
|
||||
@http.route('/mail/method', type='http', auth='user')
|
||||
def mail_action_method(self, model, res_id, method, **kwargs):
|
||||
# only public methods / check exists
|
||||
if method.strip().startswith('_') or model not in request.env:
|
||||
return self._redirect_to_messaging()
|
||||
Model = request.env[model]
|
||||
try:
|
||||
record = Model.browse(int(res_id)).exists()
|
||||
getattr(record, method)(**json.loads(kwargs.get('params', {})))
|
||||
except:
|
||||
return self._redirect_to_messaging()
|
||||
return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
|
||||
|
||||
@http.route('/mail/assign', type='http', auth='user')
|
||||
def mail_action_assign(self, model, res_id, **kwargs):
|
||||
if model not in request.env:
|
||||
return self._redirect_to_messaging()
|
||||
Model = request.env[model]
|
||||
try:
|
||||
Model.browse(int(res_id)).exists().write({'user_id': request.uid})
|
||||
except:
|
||||
return self._redirect_to_messaging()
|
||||
return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
|
||||
|
||||
@http.route('/mail/workflow', type='http', auth='user')
|
||||
def mail_action_workflow(self, model, res_id, signal, **kwargs):
|
||||
if model not in request.env:
|
||||
return self._redirect_to_messaging()
|
||||
Model = request.env[model]
|
||||
try:
|
||||
Model.browse(int(res_id)).exists().signal_workflow(signal)
|
||||
except:
|
||||
return self._redirect_to_messaging()
|
||||
return werkzeug.utils.redirect('/mail/view?%s' % url_encode({'model': model, 'res_id': res_id}))
|
||||
@http.route('/mail/assign', type='http', auth='user', methods=['GET'])
|
||||
def mail_action_assign(self, model, res_id, token=None):
|
||||
comparison, record, redirect = self._check_token_and_record_or_redirect(model, int(res_id), token)
|
||||
if comparison and record:
|
||||
try:
|
||||
record.write({'user_id': request.uid})
|
||||
except Exception:
|
||||
return self._redirect_to_messaging()
|
||||
return redirect
|
||||
|
||||
@http.route('/mail/<string:res_model>/<int:res_id>/avatar/<int:partner_id>', type='http', auth='public')
|
||||
def avatar(self, res_model, res_id, partner_id):
|
||||
|
||||
@@ -4,6 +4,8 @@ import base64
|
||||
import datetime
|
||||
import dateutil
|
||||
import email
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import lxml
|
||||
from lxml import etree
|
||||
@@ -573,6 +575,13 @@ class MailThread(models.AbstractModel):
|
||||
because portal users have a different Inbox action than classic users. """
|
||||
return 'mail.mail_channel_action_client_chat'
|
||||
|
||||
@api.model
|
||||
def _generate_notification_token(self, base_link, params):
|
||||
secret = self.env['ir.config_parameter'].sudo().get_param('database.secret')
|
||||
token = '%s?%s' % (base_link, ' '.join('%s=%s' % (key, params[key]) for key in sorted(params.keys())))
|
||||
hm = hmac.new(str(secret), token, hashlib.sha1).hexdigest()
|
||||
return hm
|
||||
|
||||
@api.multi
|
||||
def _notification_link_helper(self, link_type, **kwargs):
|
||||
if kwargs.get('message_id'):
|
||||
@@ -580,26 +589,30 @@ class MailThread(models.AbstractModel):
|
||||
'message_id': kwargs.pop('message_id')
|
||||
}
|
||||
else:
|
||||
self.ensure_one()
|
||||
base_params = {
|
||||
'model': self._name,
|
||||
'res_id': self.ids[0],
|
||||
'model': kwargs.get('model', self._name),
|
||||
'res_id': kwargs.get('res_id', self.ids and self.ids[0] or False),
|
||||
}
|
||||
|
||||
link = False
|
||||
if link_type in ['view', 'assign', 'follow', 'unfollow']:
|
||||
params = dict(base_params)
|
||||
link = '/mail/view?%s' % url_encode(params)
|
||||
elif link_type == 'workflow':
|
||||
params = dict(base_params, signal=kwargs['signal'])
|
||||
link = '/mail/workflow?%s' % url_encode(params)
|
||||
elif link_type == 'method':
|
||||
method = kwargs.pop('method')
|
||||
params = dict(base_params, method=method, params=json.dumps(kwargs))
|
||||
link = '/mail/method?%s' % url_encode(params)
|
||||
base_link = '/mail/%s' % link_type
|
||||
elif link_type == 'new':
|
||||
params = dict(base_params, action_id=kwargs.get('action_id'))
|
||||
link = '/mail/new?%s' % url_encode(params)
|
||||
params = dict(base_params, action_id=kwargs.get('action_id', ''))
|
||||
base_link = '/mail/new'
|
||||
elif link_type == 'controller':
|
||||
controller = kwargs.pop('controller')
|
||||
params = dict(base_params)
|
||||
params.pop('model')
|
||||
base_link = '%s' % controller
|
||||
else:
|
||||
return ''
|
||||
|
||||
if link_type not in ['view', 'new']:
|
||||
token = self._generate_notification_token(base_link, params)
|
||||
params['token'] = token
|
||||
|
||||
link = '%s?%s' % (base_link, url_encode(params))
|
||||
return link
|
||||
|
||||
@api.multi
|
||||
@@ -673,8 +686,8 @@ class MailThread(models.AbstractModel):
|
||||
'followers': self.env['res.partner'],
|
||||
'not_followers': self.env['res.partner'],
|
||||
'button_access': {'url': access_link, 'title': view_title},
|
||||
'button_follow': {'url': '/mail/follow?%s' % url_encode({'model': message.model, 'res_id': message.res_id}), 'title': _('Follow')},
|
||||
'button_unfollow': {'url': '/mail/unfollow?%s' % url_encode({'model': message.model, 'res_id': message.res_id}), 'title': _('Unfollow')},
|
||||
'button_follow': {'url': self._notification_link_helper('follow', model=message.model, res_id=message.res_id), 'title': _('Follow')},
|
||||
'button_unfollow': {'url': self._notification_link_helper('unfollow', model=message.model, res_id=message.res_id), 'title': _('Unfollow')},
|
||||
'actions': list(),
|
||||
}
|
||||
group_data[category] = self.env['res.partner']
|
||||
|
||||
@@ -494,6 +494,7 @@ class Users(models.Model):
|
||||
if not passwd:
|
||||
# empty passwords disallowed for obvious security reasons
|
||||
raise AccessDenied()
|
||||
db = self.pool.db_name
|
||||
if self.__uid_cache[db].get(uid) == passwd:
|
||||
return
|
||||
cr = self.pool.cursor()
|
||||
|
||||
+20
-23
@@ -26,11 +26,8 @@ from openerp import SUPERUSER_ID
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
# Import of XML records requires the unsafe eval as well,
|
||||
# almost everywhere, which is ok because it supposedly comes
|
||||
# from trusted data, but at least we make it obvious now.
|
||||
unsafe_eval = eval
|
||||
from .safe_eval import safe_eval as eval
|
||||
from .safe_eval import safe_eval as s_eval
|
||||
safe_eval = lambda expr, ctx={}: s_eval(expr, ctx, nocopy=True)
|
||||
|
||||
class ParseError(Exception):
|
||||
def __init__(self, msg, text, filename, lineno):
|
||||
@@ -98,7 +95,7 @@ def _eval_xml(self, node, env):
|
||||
idref2 = {}
|
||||
if f_search:
|
||||
idref2 = _get_idref(self, env, f_model, self.idref)
|
||||
q = unsafe_eval(f_search, idref2)
|
||||
q = safe_eval(f_search, idref2)
|
||||
ids = env[f_model].search(q).ids
|
||||
if f_use != 'id':
|
||||
ids = map(lambda x: x[f_use], env[f_model].browse(ids).read([f_use]))
|
||||
@@ -115,7 +112,7 @@ def _eval_xml(self, node, env):
|
||||
if a_eval:
|
||||
idref2 = _get_idref(self, env, f_model, self.idref)
|
||||
try:
|
||||
return unsafe_eval(a_eval, idref2)
|
||||
return safe_eval(a_eval, idref2)
|
||||
except Exception:
|
||||
logging.getLogger('openerp.tools.convert.init').error(
|
||||
'Could not eval(%s) for %s in %s', a_eval, node.get('name'), env.context)
|
||||
@@ -183,7 +180,7 @@ def _eval_xml(self, node, env):
|
||||
# FIXME: should probably be exclusive
|
||||
if a_eval:
|
||||
self.idref['ref'] = self.id_get
|
||||
args = unsafe_eval(a_eval, self.idref)
|
||||
args = safe_eval(a_eval, self.idref)
|
||||
for n in node:
|
||||
return_val = _eval_xml(self, n, env)
|
||||
if return_val is not None:
|
||||
@@ -217,12 +214,12 @@ class xml_import(object):
|
||||
for ctx in (data_node_context, node_context):
|
||||
if ctx:
|
||||
try:
|
||||
ctx_res = unsafe_eval(ctx, eval_dict)
|
||||
ctx_res = safe_eval(ctx, eval_dict)
|
||||
if isinstance(context, dict):
|
||||
context.update(ctx_res)
|
||||
else:
|
||||
context = ctx_res
|
||||
except NameError:
|
||||
except (ValueError, NameError):
|
||||
# Some contexts contain references that are only valid at runtime at
|
||||
# client-side, so in that case we keep the original context string
|
||||
# as it is. We also log it, just in case.
|
||||
@@ -261,7 +258,7 @@ form: module.record_id""" % (xml_id,)
|
||||
if d_search:
|
||||
idref = _get_idref(self, self.env, d_model, {})
|
||||
try:
|
||||
records = records.search(unsafe_eval(d_search, idref))
|
||||
records = records.search(safe_eval(d_search, idref))
|
||||
except ValueError:
|
||||
_logger.warning('Skipping deletion for failed search `%r`', d_search, exc_info=True)
|
||||
pass
|
||||
@@ -293,14 +290,14 @@ form: module.record_id""" % (xml_id,)
|
||||
if rec.get(field):
|
||||
res[dest] = rec.get(field).encode('utf8')
|
||||
if rec.get('auto'):
|
||||
res['auto'] = eval(rec.get('auto','False'))
|
||||
res['auto'] = safe_eval(rec.get('auto','False'))
|
||||
if rec.get('sxw'):
|
||||
sxw_content = file_open(rec.get('sxw')).read()
|
||||
res['report_sxw_content'] = sxw_content
|
||||
if rec.get('header'):
|
||||
res['header'] = eval(rec.get('header','False'))
|
||||
res['header'] = safe_eval(rec.get('header','False'))
|
||||
|
||||
res['multi'] = rec.get('multi') and eval(rec.get('multi','False'))
|
||||
res['multi'] = rec.get('multi') and safe_eval(rec.get('multi','False'))
|
||||
|
||||
xml_id = rec.get('id','').encode('utf8')
|
||||
self._test_xml_id(xml_id)
|
||||
@@ -324,12 +321,12 @@ form: module.record_id""" % (xml_id,)
|
||||
id = self.env['ir.model.data']._update("ir.actions.report.xml", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
|
||||
self.idref[xml_id] = int(id)
|
||||
|
||||
if not rec.get('menu') or eval(rec.get('menu','False')):
|
||||
if not rec.get('menu') or safe_eval(rec.get('menu','False')):
|
||||
keyword = str(rec.get('keyword', 'client_print_multi'))
|
||||
value = 'ir.actions.report.xml,'+str(id)
|
||||
action = self.env['ir.values'].set_action(res['name'], keyword, res['model'], value)
|
||||
self.env['ir.actions.report.xml'].browse(id).write({'ir_values_id': action.id})
|
||||
elif self.mode=='update' and eval(rec.get('menu','False'))==False:
|
||||
elif self.mode=='update' and safe_eval(rec.get('menu','False'))==False:
|
||||
# Special check for report having attribute menu=False on update
|
||||
value = 'ir.actions.report.xml,'+str(id)
|
||||
self._remove_ir_values(res['name'], value, res['model'])
|
||||
@@ -398,8 +395,8 @@ form: module.record_id""" % (xml_id,)
|
||||
context = self.get_context(data_node, rec, eval_context)
|
||||
|
||||
try:
|
||||
domain = unsafe_eval(domain, eval_context)
|
||||
except NameError:
|
||||
domain = safe_eval(domain, eval_context)
|
||||
except (ValueError, NameError):
|
||||
# Some domains contain references that are only valid at runtime at
|
||||
# client-side, so in that case we keep the original domain string
|
||||
# as it is. We also log it, just in case.
|
||||
@@ -435,7 +432,7 @@ form: module.record_id""" % (xml_id,)
|
||||
if rec.get('target'):
|
||||
res['target'] = rec.get('target','')
|
||||
if rec.get('multi'):
|
||||
res['multi'] = eval(rec.get('multi', 'False'))
|
||||
res['multi'] = safe_eval(rec.get('multi', 'False'))
|
||||
id = self.env['ir.model.data']._update('ir.actions.act_window', self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
|
||||
self.idref[xml_id] = int(id)
|
||||
|
||||
@@ -583,7 +580,7 @@ form: module.record_id""" % (xml_id,)
|
||||
if rec_id:
|
||||
records = env[rec_model].browse(self.id_get(rec_id))
|
||||
elif rec_src:
|
||||
q = unsafe_eval(rec_src, eval_dict)
|
||||
q = safe_eval(rec_src, eval_dict)
|
||||
records = env[rec_model].search(q)
|
||||
if rec_src_count:
|
||||
count = int(rec_src_count)
|
||||
@@ -609,7 +606,7 @@ form: module.record_id""" % (xml_id,)
|
||||
f_expr = test.get("expr",'').encode('utf-8')
|
||||
env = self.env(user=uid, context=context)
|
||||
expected_value = _eval_xml(self, test, env) or True
|
||||
expression_value = unsafe_eval(f_expr, globals_dict)
|
||||
expression_value = safe_eval(f_expr, globals_dict)
|
||||
if expression_value != expected_value: # assertion failed
|
||||
self.assertion_report.record_failure()
|
||||
msg = 'assertion "%s" failed!\n' \
|
||||
@@ -628,7 +625,7 @@ form: module.record_id""" % (xml_id,)
|
||||
rec_id = rec.get("id",'').encode('ascii')
|
||||
rec_context = rec.get("context", {})
|
||||
if rec_context:
|
||||
rec_context = unsafe_eval(rec_context)
|
||||
rec_context = safe_eval(rec_context)
|
||||
|
||||
if self.xml_filename and rec_id:
|
||||
rec_context['install_mode_data'] = dict(
|
||||
@@ -676,7 +673,7 @@ form: module.record_id""" % (xml_id,)
|
||||
f_val = False
|
||||
|
||||
if f_search:
|
||||
q = unsafe_eval(f_search, self.idref)
|
||||
q = safe_eval(f_search, self.idref)
|
||||
assert f_model, 'Define an attribute model="..." in your .XML file !'
|
||||
# browse the objects searched
|
||||
s = self.env[f_model].search(q)
|
||||
|
||||
Reference in New Issue
Block a user