[FIX] web: fix evaluation context of the domain selector

The domain was instantiated without being given any evaluation context.
As a result, the uid variable was not defined,
crashing the js if present in a user-defined filter.

opw 1866852
This commit is contained in:
Aaron Bohy
2018-08-30 14:55:06 +02:00
committed by len-odoo
parent 1ece9412be
commit 68332a0177
4 changed files with 58 additions and 18 deletions
@@ -2264,19 +2264,18 @@ var FieldDomain = AbstractField.extend({
// Convert char value to array value // Convert char value to array value
var value = this.value || "[]"; var value = this.value || "[]";
var domain = Domain.prototype.stringToArray(value);
// Create the domain selector or change the value of the current one... // Create the domain selector or change the value of the current one...
var def; var def;
if (!this.domainSelector) { if (!this.domainSelector) {
this.domainSelector = new DomainSelector(this, this._domainModel, domain, { this.domainSelector = new DomainSelector(this, this._domainModel, value, {
readonly: this.mode === "readonly" || this.inDialog, readonly: this.mode === "readonly" || this.inDialog,
filters: this.fsFilters, filters: this.fsFilters,
debugMode: session.debug, debugMode: session.debug,
}); });
def = this.domainSelector.prependTo(this.$el); def = this.domainSelector.prependTo(this.$el);
} else { } else {
def = this.domainSelector.setDomain(domain); def = this.domainSelector.setDomain(value);
} }
// ... then replace the other content (matched records, etc) // ... then replace the other content (matched records, etc)
return def.then(this._replaceContent.bind(this)); return def.then(this._replaceContent.bind(this));
@@ -2429,11 +2429,11 @@ var BasicModel = AbstractModel.extend({
} }
var def = $.Deferred(); var def = $.Deferred();
var evalContext = this._getEvalContext(record);
this._rpc({ this._rpc({
model: domainModel, model: domainModel,
method: 'search_count', method: 'search_count',
args: [Domain.prototype.stringToArray(domainValue)], args: [Domain.prototype.stringToArray(domainValue, evalContext)],
context: context context: context
}) })
.then(_.identity, function (error, e) { .then(_.identity, function (error, e) {
@@ -177,18 +177,12 @@ var DomainTree = DomainNode.extend({
* operator from the domain. * operator from the domain.
* @see DomainTree._addFlattenedChildren * @see DomainTree._addFlattenedChildren
*/ */
init: function (parent, model, domain, options) { init: function (parent, model, domain) {
this._super.apply(this, arguments); this._super.apply(this, arguments);
try { var parsedDomain = this._parseDomain(domain);
domain = Domain.prototype.stringToArray(domain); if (parsedDomain) {
} catch (err) { this._initialize(parsedDomain);
// TODO: domain could contain `parent` for example, which is
// currently not handled by the DomainSelector
this.invalidDomain = true;
this.children = [];
return;
} }
this._initialize(domain);
}, },
/** /**
* @see DomainNode.start * @see DomainNode.start
@@ -386,6 +380,23 @@ var DomainTree = DomainNode.extend({
}); });
}).bind(this)); }).bind(this));
}, },
/**
* @param {string} domain
* @returns {Array[]}
*/
_parseDomain: function (domain) {
var parsedDomain = false;
try {
parsedDomain = Domain.prototype.stringToArray(domain);
this.invalidDomain = false;
} catch (err) {
// TODO: domain could contain `parent` for example, which is
// currently not handled by the DomainSelector
this.invalidDomain = true;
this.children = [];
}
return parsedDomain;
},
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Handlers // Handlers
@@ -471,14 +482,17 @@ var DomainSelector = DomainTree.extend({
* If the internal domain value was already equal to the given one, this * If the internal domain value was already equal to the given one, this
* does nothing. * does nothing.
* *
* @param {Array|string} domain * @param {string} domain
* @returns {Deferred} resolved when the rerendering is finished * @returns {Deferred} resolved when the rerendering is finished
*/ */
setDomain: function (domain) { setDomain: function (domain) {
if (Domain.prototype.arrayToString(domain) === Domain.prototype.arrayToString(this.getDomain())) { if (domain === Domain.prototype.arrayToString(this.getDomain())) {
return $.when(); return $.when();
} }
return this._redraw(domain); var parsedDomain = this._parseDomain(domain);
if (parsedDomain) {
return this._redraw(domain);
}
}, },
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@@ -4345,6 +4345,33 @@ QUnit.module('basic_fields', {
QUnit.module('FieldDomain'); QUnit.module('FieldDomain');
QUnit.test('The domain editor should not crash the view when given a dynamic filter', function (assert) {
//dynamic filters (containing variables, such as uid, parent or today)
//are not handled by the domain editor, but it shouldn't crash the view
assert.expect(1);
this.data.partner.records[0].foo = '[["int_field", "=", uid]]';
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch:
'<form>' +
'<field name="foo" widget="domain" options="{\'model\': \'partner\'}"/>' +
'<field name="int_field" invisible="1"/>' +
'</form>',
res_id: 1,
session: {
user_context: {uid: 14},
},
});
assert.strictEqual(form.$('.o_read_mode').text(), "This domain is not supported.",
"The widget should not crash the view, but gracefully admit its failure.");
form.destroy();
});
QUnit.test('basic domain field usage is ok', function (assert) { QUnit.test('basic domain field usage is ok', function (assert) {
assert.expect(6); assert.expect(6);