Files
odoo_source/addons/spreadsheet/static/src/data_sources/data_source.js
T
Rémi Rahir 3e7bdd40fa [FIX] spreadsheet: Catch access errors on spreadsheet
Currently, a user opening a spreadsheet containing pivots/lists/graphs
that they don't have the rights to access (be it because of the parent
model or the domain applied) will end up in an infinite loop.

While starting the datasources, the fetch step will throw, potentially
spamming the user with access errors.

Manual forward port of https://github.com/odoo/enterprise/pull/35146

Task 3107650

closes odoo/odoo#110113

X-original-commit: 1555e79be0b52c30df43e8de50f5db56fbbda630
Signed-off-by: Rémi Rahir (rar) <rar@odoo.com>
Signed-off-by: Pierre Rousseau (pro) <pro@odoo.com>
2023-01-17 14:16:34 +01:00

100 lines
2.7 KiB
JavaScript

/** @odoo-module */
import { LoadingDataError } from "@spreadsheet/o_spreadsheet/errors";
import { RPCError } from "@web/core/network/rpc_service";
import { KeepLast } from "@web/core/utils/concurrency";
/**
* DataSource is an abstract class that contains the logic of fetching and
* maintaining access to data that have to be loaded.
*
* A class which extends this class have to implement the `_load` method
* * which should load the data it needs
*
* Subclass can implement concrete methods to have access to a
* particular data.
*/
export class LoadableDataSource {
constructor(services) {
this._orm = services.orm;
this._metadataRepository = services.metadataRepository;
this._notify = services.notify;
/**
* Last time that this dataSource has been updated
*/
this._lastUpdate = undefined;
this._concurrency = new KeepLast();
/**
* Promise to control the loading of data
*/
this._loadPromise = undefined;
this._isFullyLoaded = false;
this._isValid = true;
this._loadErrorMessage = "";
}
/**
* Load data in the model
* @param {object} [params] Params for fetching data
* @param {boolean} [params.reload=false] Force the reload of the data
*
* @returns {Promise} Resolved when data are fetched.
*/
async load(params) {
if (params && params.reload) {
this._loadPromise = undefined;
}
if (!this._loadPromise) {
this._isFullyLoaded = false;
this._isValid = true;
this._loadErrorMessage = "";
this._loadPromise = this._concurrency
.add(this._load())
.catch((e) => {
this._isValid = false;
this._loadErrorMessage = e instanceof RPCError ? e.data.message : e.message;
})
.finally(() => {
this._lastUpdate = Date.now();
this._isFullyLoaded = true;
this._notify();
});
}
return this._loadPromise;
}
get lastUpdate() {
return this._lastUpdate;
}
/**
* @returns {boolean}
*/
isReady() {
return this._isFullyLoaded;
}
/**
* @protected
*/
_assertDataIsLoaded() {
if (!this._isFullyLoaded) {
this.load();
throw new LoadingDataError();
}
if (!this._isValid) {
throw new Error(this._loadErrorMessage);
}
}
/**
* Load the data in the model
*
* @abstract
* @protected
*/
async _load() {}
}