[IMP] web,*: remove web.session

This commit removes the legacy session and adapts the modules where it
was used.

task 3439226

closes odoo/odoo#133153

Related: odoo/enterprise#46290
Signed-off-by: Jorge Pinna Puissant (jpp) <jpp@odoo.com>
This commit is contained in:
Michael (mcm)
2023-08-29 11:10:47 +00:00
parent 629a046e03
commit 1f5e8f0fd4
43 changed files with 152 additions and 1029 deletions
@@ -5,6 +5,7 @@ import { markup } from "@odoo/owl";
import { InputConfirmationDialog } from "@portal/js/components/input_confirmation_dialog/input_confirmation_dialog";
import { handleCheckIdentity } from "@portal/js/portal_security";
import publicWidget from "@web/legacy/js/public/public_widget";
import { session } from "@web/session";
/**
* Replaces specific <field> elements by normal HTML, strip out the rest entirely
@@ -144,7 +145,7 @@ publicWidget.registry.TOTPButton = publicWidget.Widget.extend({
const w = await handleCheckIdentity(this.proxy('_rpc'), this._rpc({
model: 'res.users',
method: 'action_totp_enable_wizard',
args: [this.getSession().user_id]
args: [session.user_id]
}), (...args) => this.call("dialog", "add", ...args));
if (!w) {
@@ -219,7 +220,7 @@ publicWidget.registry.DisableTOTPButton = publicWidget.Widget.extend({
e.preventDefault();
await handleCheckIdentity(
this.proxy('_rpc'),
this._rpc({model: 'res.users', method: 'action_totp_disable', args: [this.getSession().user_id]}),
this._rpc({model: 'res.users', method: 'action_totp_disable', args: [session.user_id]}),
(...args) => this.call("dialog", "add", ...args)
)
window.location = window.location;
@@ -258,7 +259,7 @@ publicWidget.registry.RevokeAllTrustedDevicesButton = publicWidget.Widget.extend
this._rpc({
model: 'res.users',
method: 'revoke_all_devices',
args: [this.getSession().user_id]
args: [session.user_id]
}),
(...args) => this.call("dialog", "add", ...args)
);
@@ -1,7 +1,7 @@
/** @odoo-module */
import { useService } from '@web/core/utils/hooks';
import session from 'web.session';
import { getCurrency } from '@web/core/currency';
const { Component, onWillStart, useState } = owl;
@@ -23,7 +23,7 @@ export class ExpenseDashboard extends Component {
renderMonetaryField(value, currency_id) {
value = value.toFixed(2);
const currency = session.get_currency(currency_id);
const currency = getCurrency(currency_id);
if (currency) {
if (currency.position === "after") {
value += currency.symbol;
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { _t } from "@web/core/l10n/translation";
import session from 'web.session'
import { session } from "@web/session";
import { useService } from "@web/core/utils/hooks";
/**
@@ -4,7 +4,6 @@ import ajax from "@web/legacy/js/core/ajax";
import { escape } from "@web/core/utils/strings";
import { whenReady } from "@odoo/owl";
import { _t } from "@web/core/l10n/translation";
import session from "web.session";
whenReady(() => {
var email = $("input[name='email']").val();
@@ -13,7 +12,6 @@ whenReady(() => {
var token = (location.search.split('token' + '=')[1] || '').split('&')[0];
if ($('.o_unsubscribe_form').length) {
session.load_translations().then(function () {
if (email != '' && email != undefined){
ajax.jsonRpc('/mailing/blacklist/check', 'call', {'email': email, 'mailing_id': mailing_id, 'res_id': res_id, 'token': token})
.then(function (result) {
@@ -55,7 +53,6 @@ whenReady(() => {
else{
$('#subscription_info').html(_t('You have been <strong>successfully unsubscribed</strong>.'));
}
});
$('#unsubscribe_form').on('submit', function (e) {
e.preventDefault();
@@ -113,9 +113,7 @@
'web/static/src/legacy/js/core/mixins.js',
'web/static/src/legacy/js/core/rpc.js',
'web/static/src/legacy/js/core/service_mixins.js',
'web/static/src/legacy/js/core/session.js',
'web/static/src/legacy/js/core/time.js',
'web/static/src/legacy/js/core/translation.js',
'web/static/src/legacy/js/core/utils.js',
'web/static/src/legacy/js/core/widget.js',
'web/static/src/legacy/js/services/core.js',
@@ -172,7 +170,6 @@
'web/static/src/legacy/backend_utils.js',
'web/static/src/legacy/utils.js',
'web/static/src/legacy/js/core/dates.js',
'web/static/src/legacy/js/services/session.js',
'web/static/src/legacy/js/env.js',
'web/static/src/legacy/js/owl_compatibility.js',
@@ -3,7 +3,7 @@
import { ConfirmationDialog } from '@web/core/confirmation_dialog/confirmation_dialog';
import { renderToMarkup } from "@web/core/utils/render";
import publicWidget from '@web/legacy/js/public/public_widget';
import session from "web.session";
import { session } from "@web/session";
import { InputConfirmationDialog } from './components/input_confirmation_dialog/input_confirmation_dialog';
import { _t } from "@web/core/l10n/translation";
@@ -2,7 +2,6 @@
import { _t } from "@web/core/l10n/translation";
import publicWidget from "@web/legacy/js/public/public_widget";
import session from "web.session";
import { deserializeDateTime } from "@web/core/l10n/dates";
const { DateTime } = luxon;
@@ -34,7 +33,6 @@ var PortalSidebar = publicWidget.Widget.extend({
diff = dateTime.diff(today).as("days"),
displayStr;
session.is_bound.then(function (){
if (diff === 0) {
displayStr = _t('Due today');
} else if (diff > 0) {
@@ -45,7 +43,6 @@ var PortalSidebar = publicWidget.Widget.extend({
displayStr = _t('%s days overdue', Math.abs(diff).toFixed(1));
}
$(el).text(displayStr);
});
});
},
/**
@@ -1,7 +1,7 @@
/** @odoo-module **/
import publicWidget from "@web/legacy/js/public/public_widget";
import session from "web.session";
import { session } from "@web/session";
import portalComposer from "@portal/js/portal_composer";
import { _t } from "@web/core/l10n/translation";
import { renderToElement } from "@web/core/utils/render";
-3
View File
@@ -164,9 +164,7 @@
'web/static/src/legacy/js/core/mixins.js',
'web/static/src/legacy/js/core/rpc.js',
'web/static/src/legacy/js/core/service_mixins.js',
'web/static/src/legacy/js/core/session.js',
'web/static/src/legacy/js/core/time.js',
'web/static/src/legacy/js/core/translation.js',
'web/static/src/legacy/js/core/utils.js',
'web/static/src/legacy/js/core/widget.js',
'web/static/src/legacy/js/services/core.js',
@@ -223,7 +221,6 @@
'web/static/src/legacy/backend_utils.js',
'web/static/src/legacy/utils.js',
'web/static/src/legacy/js/core/dates.js',
'web/static/src/legacy/js/services/session.js',
'web/static/src/legacy/js/env.js',
'web/static/src/legacy/js/owl_compatibility.js',
@@ -5,11 +5,9 @@ import { click, contains, insertText, start, startServer } from "@mail/../tests/
import {
editSelect,
selectDropdownItem,
patchWithCleanup,
patchTimeZone,
getFixture,
} from "@web/../tests/helpers/utils";
import session from "web.session";
import testUtils from "@web/../tests/legacy/helpers/test_utils";
let target;
@@ -46,11 +44,7 @@ QUnit.module("tracking value", {
return remainder;
};
patchWithCleanup(session, {
getTZOffset() {
return 0;
},
});
patchTimeZone(0);
},
});
@@ -1,15 +1,15 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import session from "web.session";
import ajax from "@web/legacy/js/core/ajax";
registry.category("web_tour.tours").add('test_json_auth', {
test: true,
steps: () => [{
trigger: 'body',
run: async function () {
await session.rpc('/test_get_dbname').then( function (result){
return session.rpc("/web/session/authenticate", {
await ajax.rpc('/test_get_dbname').then( function (result){
return ajax.rpc("/web/session/authenticate", {
db: result,
login: 'admin',
password: 'admin'
-6
View File
@@ -113,9 +113,7 @@ This module provides the core of the Odoo Web Client.
'web/static/src/legacy/js/core/mixins.js',
'web/static/src/legacy/js/core/rpc.js',
'web/static/src/legacy/js/core/service_mixins.js',
'web/static/src/legacy/js/core/session.js',
'web/static/src/legacy/js/core/time.js',
'web/static/src/legacy/js/core/translation.js',
'web/static/src/legacy/js/core/utils.js',
'web/static/src/legacy/js/core/widget.js',
'web/static/src/legacy/js/services/core.js',
@@ -163,7 +161,6 @@ This module provides the core of the Odoo Web Client.
'web/static/src/legacy/backend_utils.js',
'web/static/src/legacy/utils.js',
'web/static/src/legacy/js/core/dates.js',
'web/static/src/legacy/js/services/session.js',
'web/static/src/legacy/js/env.js',
'web/static/src/legacy/js/owl_compatibility.js',
@@ -267,9 +264,7 @@ This module provides the core of the Odoo Web Client.
'web/static/src/legacy/js/core/mixins.js',
'web/static/src/legacy/js/core/rpc.js',
'web/static/src/legacy/js/core/service_mixins.js',
'web/static/src/legacy/js/core/session.js',
'web/static/src/legacy/js/core/time.js',
'web/static/src/legacy/js/core/translation.js',
'web/static/src/legacy/js/core/utils.js',
'web/static/src/legacy/js/core/widget.js',
'web/static/src/legacy/js/services/core.js',
@@ -290,7 +285,6 @@ This module provides the core of the Odoo Web Client.
'web/static/src/legacy/utils.js',
'web/static/src/legacy/js/core/dates.js',
'web/static/src/legacy/js/owl_compatibility.js',
'web/static/src/legacy/js/services/session.js',
'web/static/src/legacy/js/public/public_env.js',
'web/static/src/legacy/js/public/public_root.js',
'web/static/src/legacy/js/public/public_root_instance.js',
+1 -85
View File
@@ -16,97 +16,13 @@
* [1] https://github.com/odoo/owl/blob/master/doc/reference/environment.md#content-of-an-environment
*/
import { jsonRpc } from "@web/legacy/js/core/ajax";
import { bus } from "@web/legacy/js/services/core";
import rpc from "@web/legacy/js/core/rpc";
import session from "web.session";
import {getCookie, setCookie} from "@web/legacy/js/core/cookie_utils";
const browser = {
clearInterval: window.clearInterval.bind(window),
clearTimeout: window.clearTimeout.bind(window),
Date: window.Date,
fetch: (window.fetch || (() => { })).bind(window),
Notification: window.Notification,
requestAnimationFrame: window.requestAnimationFrame.bind(window),
setInterval: window.setInterval.bind(window),
setTimeout: window.setTimeout.bind(window),
};
Object.defineProperty(browser, 'innerHeight', {
get: () => window.innerHeight,
});
Object.defineProperty(browser, 'innerWidth', {
get: () => window.innerWidth,
});
// Build the basic env
const env = {
browser,
bus,
debug: odoo.debug,
services: {
ajax: {
rpc(route, args, options, target) {
let rpcPromise = null;
const promise = new Promise(function (resolve, reject) {
rpcPromise = session.rpc(route, args, options);
rpcPromise.then(function (result) {
if (!target.isDestroyed()) {
resolve(result);
}
}).guardedCatch(function (reason) {
if (!target.isDestroyed()) {
reject(reason);
}
});
});
promise.abort = rpcPromise.abort.bind(rpcPromise);
return promise;
},
},
ajaxJsonRPC() {
return jsonRpc(...arguments);
},
getCookie() {
return getCookie(...arguments);
},
httpRequest(route, params = {}, readMethod = 'json') {
const info = {
method: params.method || 'POST',
};
if (params.method !== 'GET') {
const formData = new FormData();
for (const key in params) {
if (key === 'method') {
continue;
}
const value = params[key];
if (Array.isArray(value) && value.length) {
for (const val of value) {
formData.append(key, val);
}
} else {
formData.append(key, value);
}
}
info.body = formData;
}
return fetch(route, info).then(response => response[readMethod]());
},
navigate(url, params) {
window.location = $.param.querystring(url, params);
},
reloadPage() {
window.location.reload();
},
rpc(params, options) {
const query = rpc.buildQuery(params);
return session.rpc(query.route, query.params, options);
},
setCookie() {
setCookie(...arguments);
},
},
session,
services: {},
};
export default env;
@@ -3,10 +3,7 @@
import core from "@web/legacy/js/services/core";
import { Markup } from "@web/legacy/js/core/utils";
import time from "@web/legacy/js/core/time";
import download from "@web/legacy/js/libs/download";
import contentdisposition from "@web/legacy/js/libs/content-disposition";
import { session } from "@web/session";
import { _t } from "@web/core/l10n/translation";
// Create the final object containing all the functions first to allow monkey
// patching them correctly if ever needed.
@@ -70,9 +67,6 @@ function _genericJsonRpc (fct_name, params, settings, fct) {
if (!shadow) {
core.bus.trigger('rpc_response', data.id);
}
if (error.code === 100) {
core.bus.trigger('invalidate_session');
}
reject({message: error, event: $.Event()});
} else {
if (!shadow) {
@@ -138,100 +132,6 @@ function rpc(url, params, settings) {
return jsonRpc(url, 'call', params, settings);
}
/**
* Cooperative file download implementation, for ajaxy APIs.
*
* @param {Object} options
* @param {String} [options.url] used to dynamically create a form
* @param {Object} [options.data] data to add to the form submission. If can be used without a form, in which case a form is created from scratch. Otherwise, added to form data
* @param {HTMLFormElement} [options.form] the form to submit in order to fetch the file
* @param {Function} [options.success] callback in case of download success
* @param {Function} [options.error] callback in case of request error, provided with the error body
* @param {Function} [options.complete] called after both ``success`` and ``error`` callbacks have executed
* @returns {boolean} a false value means that a popup window was blocked. This
* mean that we probably need to inform the user that something needs to be
* changed to make it work.
*/
function get_file(options) {
var xhr = new XMLHttpRequest();
var data;
if (options.form) {
xhr.open(options.form.method, options.form.action);
data = new FormData(options.form);
} else {
xhr.open('POST', options.url);
data = new FormData();
for (const [k, v] of Object.entries(options.data || {})) {
data.append(k, v);
}
}
if (odoo.csrf_token) {
data.append('csrf_token', odoo.csrf_token);
}
// IE11 wants this after xhr.open or it throws
xhr.responseType = 'blob';
// onreadystatechange[readyState = 4]
// => onload (success) | onerror (error) | onabort
// => onloadend
xhr.onload = function () {
var mimetype = xhr.response.type;
if (xhr.status === 200 && mimetype !== 'text/html') {
// replace because apparently we send some C-D headers with a trailing ";"
// todo: maybe a lack of CD[attachment] should be interpreted as an error case?
var header = (xhr.getResponseHeader('Content-Disposition') || '').replace(/;$/, '');
var filename = header ? contentdisposition.parse(header).parameters.filename : null;
download(xhr.response, filename, mimetype);
// not sure download is going to be sync so this may be called
// before the file is actually fetched (?)
if (options.success) { options.success(); }
return true;
}
if (!options.error) {
return true;
}
var decoder = new FileReader();
decoder.onload = function () {
var contents = decoder.result;
var err;
var doc = new DOMParser().parseFromString(contents, 'text/html');
var nodes = doc.body.children.length === 0 ? doc.body.childNodes : doc.body.children;
try { // Case of a serialized Odoo Exception: It is Json Parsable
var node = nodes[1] || nodes[0];
err = JSON.parse(node.textContent);
} catch { // Arbitrary uncaught python side exception
err = {
message: nodes.length > 1 ? nodes[1].textContent : '',
data: {
name: String(xhr.status),
title: nodes.length > 0 ? nodes[0].textContent : '',
}
};
}
options.error(err);
};
decoder.readAsText(xhr.response);
};
xhr.onerror = function () {
if (options.error) {
options.error({
message: _t("Something happened while trying to contact the server, check that the server is online and that you still have a working network connection."),
data: { title: _t("Could not connect to the server") }
});
}
};
if (options.complete) {
xhr.onloadend = function () { options.complete(); };
}
xhr.send(data);
return true;
}
function post (controller_url, data) {
var postData = new FormData();
@@ -318,7 +218,6 @@ Object.assign(ajax, {
jsonRpc: jsonRpc,
rpc: rpc,
loadAsset: loadAsset,
get_file: get_file,
post: post,
});
@@ -1,11 +1,14 @@
/** @odoo-module **/
import session from "web.session";
import time from "@web/legacy/js/core/time";
import { _t } from "@web/core/l10n/translation";
const { DateTime } = luxon;
function getTimezoneOffset(value) {
return luxon.Settings.defaultZone.offset(value.valueOf());
}
/**
* Returns a string representing a date. If the value is false, then we return
* an empty string. Note that this is dependant on the localization settings
@@ -24,7 +27,7 @@ export function formatDate(value, field, options) {
}
if (field && field.type === 'datetime') {
if (!options || !('timezone' in options) || options.timezone) {
value = value.clone().add(session.getTZOffset(value), 'minutes');
value = value.clone().add(getTimezoneOffset(value), 'minutes');
}
}
var date_format = time.getLangDateFormat();
@@ -49,7 +52,7 @@ export function formatDateTime(value, field, options) {
return "";
}
if (!options || !('timezone' in options) || options.timezone) {
value = value.clone().add(session.getTZOffset(value), 'minutes');
value = value.clone().add(getTimezoneOffset(value), 'minutes');
}
return value.format(time.getLangDatetimeFormat());
}
@@ -170,7 +173,7 @@ export function parseDateTime(value, field, options) {
} else {
datetime = moment.utc(value, [pattern1, pattern2, moment.ISO_8601]);
if (options && options.timezone) {
datetime.add(-session.getTZOffset(datetime), 'minutes');
datetime.add(-getTimezoneOffset(datetime), 'minutes');
}
}
}
@@ -92,16 +92,6 @@ var ServicesMixin = {
});
});
},
// Session stuff
getSession: function () {
var session;
this.trigger_up('get_session', {
callback: function (result) {
session = result;
}
});
return session;
},
/**
* Informs the action manager to do an action. This supposes that the action
* manager can be found amongst the ancestors of the current widget.
@@ -1,354 +0,0 @@
/** @odoo-module **/
import ajax from "@web/legacy/js/core/ajax";
import Class from "@web/legacy/js/core/class";
import core from "@web/legacy/js/services/core";
import mixins from "@web/legacy/js/core/mixins";
import {setCookie} from "@web/legacy/js/core/cookie_utils";
import { session } from "@web/session";
import { loadJS } from "@web/core/assets";
import { _t } from "@web/legacy/js/core/translation";
// To do: refactor session. Session accomplishes several concerns (rpc,
// configuration, currencies (wtf?), user permissions...). They should be
// clarified and separated.
var Session = Class.extend(mixins.EventDispatcherMixin, {
/**
@param parent The parent of the newly created object.
or `null` if the server to contact is the origin server.
@param {Dict} options A dictionary that can contain the following options:
* "modules"
* "use_cors"
*/
init: function (parent, origin, options) {
mixins.EventDispatcherMixin.init.call(this);
this.setParent(parent);
options = options || {};
this.server = null;
this.avoid_recursion = false;
this.use_cors = options.use_cors || false;
this.setup(origin);
// for historic reasons, the session requires a name to properly work
// (see the methods get_cookie and set_cookie). We should perhaps
// remove it totally (but need to make sure the cookies are properly set)
this.name = "instance0";
// TODO: session store in cookie should be optional
this.currencies = {};
this._groups_def = {};
core.bus.on('invalidate_session', this, this._onInvalidateSession);
},
setup: function (origin, options) {
// must be able to customize server
var window_origin = location.protocol + "//" + location.host;
origin = origin ? origin.replace( /\/+$/, '') : window_origin;
if (typeof this.origin !== "undefined" && this.origin !== origin)
throw new Error('Session already bound to ' + this.origin);
else
this.origin = origin;
this.prefix = this.origin;
this.server = this.origin; // keep chs happy
options = options || {};
if ('use_cors' in options) {
this.use_cors = options.use_cors;
}
},
/**
* Setup a session
*/
session_bind: function (origin) {
this.setup(origin);
this.uid = null;
this.username = null;
this.user_context= {};
this.db = null;
this.active_id = null;
return this.session_init();
},
/**
* Init a session, reloads from cookie, if it exists
*/
session_init: function () {
var self = this;
var prom = this.session_reload();
if (this.is_frontend || this.is_report) {
return prom.then(function () {
return self.load_translations();
});
}
return prom.then(function () {
var promise = self.load_qweb();
if (self.session_is_valid()) {
return promise.then(function () { return self.load_modules(); });
}
return Promise.all([
promise,
self.rpc('/web/webclient/bootstrap_translations')
.then(function (trans) {
_t.database.set_bundle(trans);
})
]);
});
},
session_is_valid: function () {
var db = $.deparam.querystring().db;
if (db && this.db !== db) {
return false;
}
return !!this.uid;
},
/**
* The session is validated by restoration of a previous session
*/
session_authenticate: function () {
var self = this;
return Promise.resolve(this._session_authenticate.apply(this, arguments)).then(function () {
return self.load_modules();
});
},
/**
* The session is validated either by login or by restoration of a previous session
*/
_session_authenticate: function (db, login, password) {
var self = this;
var params = {db: db, login: login, password: password};
return this.rpc("/web/session/authenticate", params).then(function (result) {
if (!result.uid) {
return Promise.reject();
}
Object.assign(self, result);
});
},
session_logout: function () {
$.bbq.removeState();
return this.rpc("/web/session/destroy", {});
},
user_has_group: function (group) {
// the frontend session info has no `uid` but an `user_id`
if (!this.uid && !this.user_id) {
return Promise.resolve(false);
}
var def = this._groups_def[group];
if (!def) {
def = this._groups_def[group] = this.rpc('/web/dataset/call_kw/res.users/has_group', {
"model": "res.users",
"method": "has_group",
"args": [group],
"kwargs": {}
});
}
return def;
},
get_cookie: function (name) {
if (!this.name) { return null; }
var nameEQ = this.name + '|' + name + '=';
var cookies = document.cookie.split(';');
for(var i=0; i<cookies.length; ++i) {
var cookie = cookies[i].replace(/^\s*/, '');
if(cookie.indexOf(nameEQ) === 0) {
try {
return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length)));
} catch {
// wrong cookie, delete it
this.set_cookie(name, '', -1);
}
}
}
return null;
},
/**
* Create a new cookie with the provided name and value
*
* @private
* @param name the cookie's name
* @param value the cookie's value
* @param ttl the cookie's time to live, 1 year by default, set to -1 to delete
* @param type the type of the cookies ('required' as default value)
*/
set_cookie(name, value, ttl, type = 'required') {
if (!this.name) { return; }
ttl = ttl || 24*60*60*365;
setCookie(this.name + '|' + name, value, ttl, type);
},
/**
* Load additional web addons of that instance and init them
*
*/
load_modules: function () {
var self = this;
var loaded = Promise.resolve(self.load_translations());
var locale = "/web/webclient/locale/" + self.user_context.lang || 'en_US';
var file_list = [ locale ];
return loaded.then(function () {
return self.load_js(file_list);
}).then(function () {
self._configureLocale();
});
},
load_translations: function (modules=null) {
var lang = this.user_context.lang
var html = document.documentElement
, htmlLang = html.getAttribute('lang');
if (!this.user_context.lang && htmlLang) {
lang = htmlLang.replace('-', '_');
}
return _t.database.load_translations(this, modules, lang, this.translationURL);
},
load_js: function (files) {
var self = this;
return new Promise(function (resolve, reject) {
if (files.length !== 0) {
var file = files.shift();
var url = self.url(file, null);
loadJS(url).then(resolve);
} else {
resolve();
}
});
},
load_qweb: async function () {
await odoo.ready(/\.bundle\.xml$/);
},
get_currency: function (currency_id) {
return this.currencies[currency_id];
},
get_file: function (options) {
options.session = this;
return ajax.get_file(options);
},
/**
* (re)loads the content of a session: db name, username, user id, session
* context and status of the support contract
*
* @returns {Promise} promise indicating the session is done reloading
*/
session_reload: function () {
var result = Object.assign({}, session);
Object.assign(this, result);
return Promise.resolve();
},
/**
* Executes an RPC call, registering the provided callbacks.
*
* Registers a default error callback if none is provided, and handles
* setting the correct session id and session context in the parameter
* objects
*
* @param {String} url RPC endpoint
* @param {Object} params call parameters
* @param {Object} options additional options for rpc call
* @returns {Promise}
*/
rpc: function (url, params, options) {
var self = this;
options = Object.assign({}, options || {});
options.headers = Object.assign({}, options.headers);
// we add here the user context for ALL queries, mainly to pass
// the allowed_company_ids key
if (params && params.kwargs) {
params.kwargs.context = Object.assign(params.kwargs.context || {}, this.user_context);
}
// TODO: remove
if (typeof url !== "string") {
Object.assign(options, url);
url = url.url;
}
if (self.use_cors) {
url = self.url(url, null);
}
return ajax.jsonRpc(url, "call", params, options);
},
url: function (path, params) {
params = Object.assign(params || {});
var qs = $.param(params);
if (qs.length > 0)
qs = "?" + qs;
var prefix = ['http://', 'https://', '//'].some((el) => {
return path.length >= el.length && path.slice(0, el.length) === el;
}) ? '' : this.prefix;
return prefix + path + qs;
},
/**
* Returns the time zone difference (in minutes) from the current locale
* (host system settings) to UTC, for a given date. The offset is positive
* if the local timezone is behind UTC, and negative if it is ahead.
*
* @param {string | moment} date a valid string date or moment instance
* @returns {integer}
*/
getTZOffset: function (date) {
return -new Date(new Date(date).toISOString().replace('Z', '')).getTimezoneOffset();
},
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* Replaces the value of a key in cache_hashes (the hash of some resource computed on the back-end by a unique value
* @param {string} key the key in the cache_hashes to invalidate
*/
invalidateCacheKey: function(key) {
if (this.cache_hashes && this.cache_hashes[key]) {
this.cache_hashes[key] = Date.now();
}
},
setCompanies: function (main_company_id, company_ids) {
var hash = $.bbq.getState();
hash.cids = company_ids.sort(function(a, b) {
if (a === main_company_id) {
return -1;
} else if (b === main_company_id) {
return 1;
} else {
return a - b;
}
}).join(',');
setCookie('cids', hash.cids || String(main_company_id), 24 * 60 * 60 * 365, 'required');
$.bbq.pushState({'cids': hash.cids}, 0);
location.reload();
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* Sets first day of week in current locale according to the user language.
*
* @private
*/
_configureLocale: function () {
// TODO: try to test when re - writing this file in the new system with luxon
const dow = (_t.database.parameters.week_start || 0) % 7;
moment.updateLocale(moment.locale(), {
week: {
dow: dow,
doy: 7 + dow - 4 // Note: ISO 8601 week date: https://momentjscom.readthedocs.io/en/latest/moment/07-customization/16-dow-doy/
},
});
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
*/
_onInvalidateSession: function () {
this.uid = false;
},
});
export default Session;
+15 -68
View File
@@ -1,11 +1,11 @@
/** @odoo-module **/
import translation from "@web/legacy/js/core/translation";
import { localization } from "@web/core/l10n/localization";
import utils from "@web/legacy/js/core/utils";
import { _t } from "@web/core/l10n/translation";
var lpad = utils.lpad;
var rpad = utils.rpad;
var _t = translation._t;
/**
* Replacer function for JSON.stringify, serializes Date objects to UTC
@@ -205,89 +205,37 @@ export function auto_date_to_str (value, type) {
}
}
/**
* Convert Python strftime to escaped moment.js format.
*
* @param {String} value original format
*/
export function strftime_to_moment_format (value) {
if (_normalize_format_cache[value] === undefined) {
var isletter = /[a-zA-Z]/,
output = [],
inToken = false;
for (var index=0; index < value.length; ++index) {
var character = value[index];
if (character === '%' && !inToken) {
inToken = true;
continue;
}
if (isletter.test(character)) {
if (inToken && normalize_format_table[character] !== undefined) {
character = normalize_format_table[character];
} else {
character = '[' + character + ']'; // moment.js escape
}
}
output.push(character);
inToken = false;
}
_normalize_format_cache[value] = output.join('');
}
return _normalize_format_cache[value];
}
var _normalize_format_cache = {};
var normalize_format_table = {
// Python strftime to moment.js conversion table
// See openerp/addons/base/views/res_lang_views.xml
// for details about supported directives
'a': 'ddd',
'A': 'dddd',
'b': 'MMM',
'B': 'MMMM',
'd': 'DD',
'H': 'HH',
'I': 'hh',
'j': 'DDDD',
'm': 'MM',
'M': 'mm',
'p': 'A',
'S': 'ss',
'U': 'ww',
'W': 'WW',
'w': 'd',
'y': 'YY',
'Y': 'YYYY',
// unsupported directives
'c': 'ddd MMM D HH:mm:ss YYYY',
'x': 'MM/DD/YY',
'X': 'HH:mm:ss'
const luxonToMomentFormatTable = {
c: "d",
d: "D",
o: "DDDD",
a: "A",
y: "Y",
};
var inverse_normalize_format_table = {};
Object.entries(normalize_format_table).forEach(([key, val]) => {
inverse_normalize_format_table[val] = key;
});
function luxonToMomentFormat(format) {
return format.replace(/[a-zA-Z]/g, (match) => luxonToMomentFormatTable[match] || match);
}
/**
* Get date format of the user's language
*/
export function getLangDateFormat() {
return strftime_to_moment_format(_t.database.parameters.date_format);
return luxonToMomentFormat(localization.dateFormat);
}
/**
* Get time format of the user's language
*/
export function getLangTimeFormat() {
return strftime_to_moment_format(_t.database.parameters.time_format);
return luxonToMomentFormat(localization.timeFormat);
}
/**
* Get date time format of the user's language
*/
export function getLangDatetimeFormat() {
return strftime_to_moment_format(_t.database.parameters.date_format + " " + _t.database.parameters.time_format);
return luxonToMomentFormat(localization.dateTimeFormat);
}
const dateFormatWoZeroCache = {};
@@ -329,7 +277,6 @@ export default {
time_to_str: time_to_str,
auto_str_to_date: auto_str_to_date,
auto_date_to_str: auto_date_to_str,
strftime_to_moment_format: strftime_to_moment_format,
getLangDateFormat: getLangDateFormat,
getLangTimeFormat: getLangTimeFormat,
getLangDateFormatWoZero: getLangDateFormatWoZero,
@@ -1,125 +0,0 @@
/** @odoo-module **/
import { sprintf } from "@web/core/utils/strings";
import Class from "@web/legacy/js/core/class";
var TranslationDataBase = Class.extend(/** @lends instance.TranslationDataBase# */{
init: function() {
this.db = {};
this.multi_lang = false
this.parameters = {"direction": 'ltr',
"date_format": '%m/%d/%Y',
"time_format": '%H:%M:%S',
"grouping": [],
"decimal_point": ".",
"thousands_sep": ",",
"code": "en_US"};
},
set_bundle: function(translation_bundle) {
var self = this;
this.multi_lang = translation_bundle.multi_lang
var modules = Object.keys(translation_bundle.modules);
modules.sort();
if (modules.includes("web")) {
modules = ["web"].concat(modules.filter((module) => module !== "web"));
}
modules.forEach((name) => {
self.add_module_translation(translation_bundle.modules[name]);
});
if (translation_bundle.lang_parameters) {
this.parameters = translation_bundle.lang_parameters;
this.parameters.grouping = JSON.parse(this.parameters.grouping);
}
},
add_module_translation: function(mod) {
var self = this;
mod.messages.forEach((message) => {
self.db[message.id] = message.string;
});
},
build_translation_function: function() {
var self = this;
var fcnt = function(term, ...values) {
const translation = self.get(term) ?? term;
if (values.length === 0) {
return translation;
}
return sprintf(translation, ...values);
};
fcnt.database = this;
return fcnt;
},
get: function(key) {
return this.db[key];
},
/**
Loads the translations from an OpenERP server.
@param {openerp.Session} session The session object to contact the server.
@param {Array} [modules] The list of modules to load the translation. If not specified,
it will default to all the modules installed in the current database.
@param {Object} [lang] lang The language. If not specified it will default to the language
of the current user.
@param {string} [url='/web/webclient/translations']
@returns {Promise}
*/
load_translations: function(session, modules, lang, url) {
var self = this;
var cacheId = session.cache_hashes && session.cache_hashes.translations;
url = url || '/web/webclient/translations';
url += '/' + (cacheId ? cacheId : Date.now());
const paramsGet = {};
if (modules) {
paramsGet.mods = modules.join(',');
}
if (lang) {
paramsGet.lang = lang;
} else if (session.is_frontend && session.lang_url_code) {
// Keep distinct cached responses per language.
paramsGet.unique = session.lang_url_code;
}
return $.get(url, paramsGet).then(function (trans) {
self.set_bundle(trans);
});
}
});
/**
* Eager translation function, performs translation immediately at call
* site. Beware using this outside of method bodies (before the
* translation database is loaded), you probably want :func:`_lt`
* instead.
*
* @function _t
* @param {String} source string to translate
* @returns {String} source translated into the current locale
*/
export var _t = new TranslationDataBase().build_translation_function();
/** Setup jQuery timeago */
/*
* Strings in timeago are "composed" with prefixes, words and suffixes. This
* makes their detection by our translating system impossible. Use all literal
* strings we're using with a translation mark here so the extractor can do its
* job.
*/
{
_t('less than a minute ago');
_t('about a minute ago');
_t('%d minutes ago');
_t('about an hour ago');
_t('%d hours ago');
_t('a day ago');
_t('%d days ago');
_t('about a month ago');
_t('%d months ago');
_t('about a year ago');
_t('%d years ago');
}
export default {
_t: _t,
TranslationDataBase: TranslationDataBase,
};
@@ -259,10 +259,6 @@
You should probably create a mapper in @web/legacy/utils`
);
}
} else if (evType === 'get_session') {
if (payload.callback) {
payload.callback(this.env.session);
}
} else {
payload.__targetWidget = ev.target;
this.trigger(evType.replace(/_/g, '-'), payload);
@@ -2,7 +2,6 @@
import dom from '@web/legacy/js/core/dom';
import legacyEnv from '@web/legacy/js/public/public_env';
import session from 'web.session';
import {getCookie} from '@web/legacy/js/core/cookie_utils';
import publicWidget from '@web/legacy/js/public/public_widget';
import { registry } from '@web/core/registry';
@@ -11,10 +10,10 @@ import lazyloader from "@web/legacy/js/public/lazyloader";
import {
makeLegacyNotificationService,
makeLegacySessionService,
makeLegacyDialogMappingService,
mapLegacyEnvToWowlEnv,
makeLegacyRainbowManService,
makeLegacyRPCService,
} from "../../utils";
import { standaloneAdapter } from "@web/legacy/js/owl_compatibility";
@@ -27,6 +26,7 @@ import { renderToString } from "@web/core/utils/render";
import { _t } from "@web/core/l10n/translation";
import { omit } from "@web/core/utils/objects";
import { Component, App, whenReady } from "@odoo/owl";
import { getOrigin } from '@web/core/utils/urls';
const serviceRegistry = registry.category("services");
@@ -76,7 +76,6 @@ export const PublicRoot = publicWidget.RootWidget.extend({
// TODO would be even greater to wait for localeDef only when necessary
return Promise.all([
this._super.apply(this, arguments),
session.is_bound,
localeDef
]);
},
@@ -362,7 +361,7 @@ export async function createPublicRoot(RootWidget) {
await lazyloader.allScriptsLoaded;
// add a bunch of mapping services that will redirect service calls from the legacy env
// to the wowl env
serviceRegistry.add("legacy_session", makeLegacySessionService(legacyEnv, session));
serviceRegistry.add("legacy_rpc", makeLegacyRPCService(legacyEnv));
serviceRegistry.add("legacy_notification", makeLegacyNotificationService(legacyEnv));
serviceRegistry.add("legacy_dialog_mapping", makeLegacyDialogMappingService(legacyEnv));
serviceRegistry.add("legacy_rainbowman_service", makeLegacyRainbowManService(legacyEnv));
@@ -370,11 +369,11 @@ export async function createPublicRoot(RootWidget) {
for (const [legacyServiceName, wowlToLegacyServiceMapper] of wowlToLegacyServiceMappers) {
serviceRegistry.add(legacyServiceName, wowlToLegacyServiceMapper(legacyEnv));
}
await Promise.all([whenReady(), session.is_bound]);
await whenReady();
// Patch browser.fetch and the rpc service to use the correct base url when
// embeded in an external page
const baseUrl = session.prefix;
const baseUrl = getOrigin();
const { fetch } = browser;
browser.fetch = function(url, ...args) {
if (!url.match(/^(?:https?:)?\/\//)) {
@@ -1,8 +0,0 @@
/** @odoo-module alias=web.session **/
import Session from "@web/legacy/js/core/session";
var session = new Session(undefined, undefined, {use_cors: false});
session.is_bound = session.session_bind()
export default session;
+5 -5
View File
@@ -3,15 +3,15 @@
import { registry } from "../core/registry";
import {
makeLegacyNotificationService,
makeLegacySessionService,
makeLegacyDialogMappingService,
makeLegacyCrashManagerService,
makeLegacyCommandService,
makeLegacyDropdownService,
makeMomentLoaderService,
makeLegacyRPCService,
} from "./utils";
import { makeLegacyActionManagerService } from "./backend_utils";
import legacyEnv from "@web/legacy/js/env";
import session from "web.session";
import { templates } from "@web/core/assets";
import { Component, whenReady } from "@odoo/owl";
@@ -30,8 +30,7 @@ export const legacySetupProm = new Promise((resolve) => {
serviceRegistry.add("legacy_action_manager", legacyActionManagerService);
// add a service to redirect rpc events triggered on the bus in the
// legacy env on the bus in the wowl env
const legacySessionService = makeLegacySessionService(legacyEnv, session);
serviceRegistry.add("legacy_session", legacySessionService);
serviceRegistry.add("legacy_rpc", makeLegacyRPCService(legacyEnv));
serviceRegistry.add("legacy_notification", makeLegacyNotificationService(legacyEnv));
serviceRegistry.add("legacy_crash_manager", makeLegacyCrashManagerService(legacyEnv));
const legacyDialogMappingService = makeLegacyDialogMappingService(legacyEnv);
@@ -39,11 +38,12 @@ export const legacySetupProm = new Promise((resolve) => {
const legacyCommandService = makeLegacyCommandService(legacyEnv);
serviceRegistry.add("legacy_command", legacyCommandService);
serviceRegistry.add("legacy_dropdown", makeLegacyDropdownService(legacyEnv));
serviceRegistry.add("moment", makeMomentLoaderService());
const wowlToLegacyServiceMappers = registry.category("wowlToLegacyServiceMappers").getEntries();
for (const [legacyServiceName, wowlToLegacyServiceMapper] of wowlToLegacyServiceMappers) {
serviceRegistry.add(legacyServiceName, wowlToLegacyServiceMapper(legacyEnv));
}
await Promise.all([whenReady(), session.is_bound]);
await whenReady();
legacyEnv.templates = templates;
legacySetupResolver(legacyEnv);
})();
+47 -61
View File
@@ -1,16 +1,11 @@
/** @odoo-module **/
import { browser } from "../core/browser/browser";
import {
ConnectionAbortedError,
RPCError,
makeErrorFromResponse,
ConnectionLostError,
} from "../core/network/rpc_service";
import { makeErrorFromResponse } from "../core/network/rpc_service";
import { ErrorDialog } from "../core/errors/error_dialogs";
import { useService } from "@web/core/utils/hooks";
import { Component, useComponent, xml } from "@odoo/owl";
import { loadJS } from "@web/core/assets";
export const wowlServicesSymbol = Symbol("wowlServices");
@@ -111,64 +106,10 @@ export function makeLegacyDropdownService(legacyEnv) {
};
}
export function makeLegacySessionService(legacyEnv, session) {
return {
dependencies: ["user"],
start(env) {
// userContext, Object.create is incompatible with legacy new Context
function mapContext() {
return Object.assign({}, env.services.user.context);
}
Object.defineProperty(legacyEnv.session, "userContext", {
get: () => mapContext(),
});
Object.defineProperty(session, "user_context", {
get: () => mapContext(),
});
},
};
}
export function mapLegacyEnvToWowlEnv(legacyEnv, wowlEnv) {
// store wowl services on the legacy env (used by the 'useWowlService' hook)
legacyEnv[wowlServicesSymbol] = wowlEnv.services;
// rpc
legacyEnv.session.rpc = (...args) => {
let rejection;
const prom = new Promise((resolve, reject) => {
const [route, params, settings = {}] = args;
// Add user context in kwargs if there are kwargs
if (params && params.kwargs) {
params.kwargs.context = Object.assign(
{},
legacyEnv.session.user_context,
params.kwargs.context
);
}
const jsonrpc = wowlEnv.services.rpc(route, params, {
silent: settings.shadow,
xhr: settings.xhr,
});
rejection = () => {
jsonrpc.abort();
};
jsonrpc.then(resolve).catch((reason) => {
if (reason instanceof RPCError || reason instanceof ConnectionLostError) {
// we do not reject an error here because we want to pass through
// the legacy guardedCatch code
reject({ message: reason, event: $.Event(), legacy: true });
} else if (reason instanceof ConnectionAbortedError) {
reject({ message: reason.message, event: $.Event("abort") });
} else {
reject(reason);
}
});
});
prom.abort = rejection;
return prom;
};
legacyEnv.services.dialog = wowlEnv.services.dialog;
legacyEnv.services.ui = wowlEnv.services.ui;
@@ -307,6 +248,51 @@ export function makeLegacyRainbowManService(legacyEnv) {
};
}
export function makeMomentLoaderService() {
return {
dependencies: ["localization"],
async start(_, { localization }) {
await loadJS(`/web/webclient/locale/${localization.code}`);
const dow = (localization.weekStart || 0) % 7;
moment.updateLocale(moment.locale(), {
dow,
doy: 7 + dow - 4, // Note: ISO 8601 week date: https://momentjscom.readthedocs.io/en/latest/moment/07-customization/16-dow-doy/
});
},
};
}
export function makeLegacyRPC(wowlRPC) {
return function rpc(route, args, options, target) {
let rpcPromise = null;
const promise = new Promise(function (resolve, reject) {
rpcPromise = wowlRPC(route, args, options);
rpcPromise.then(function (result) {
if (!target.isDestroyed()) {
resolve(result);
}
}).guardedCatch(function (reason) {
if (!target.isDestroyed()) {
reject(reason);
}
});
});
promise.abort = rpcPromise.abort.bind(rpcPromise);
return promise;
};
}
export function makeLegacyRPCService(legacyEnv) {
return {
dependencies: ["rpc"],
start(_, { rpc: wowlRPC }) {
const rpc = makeLegacyRPC(wowlRPC);
legacyEnv.services.ajax = { rpc };
legacyEnv.services.rpc = rpc;
},
};
}
export function useLegacyRefs() {
const env = owl.useEnv();
@@ -1,24 +0,0 @@
/** @odoo-module **/
// Override the Session.session_reload function
// The wowl test infrastructure does set a correct odoo global value before each test
// while the session is built only once for all tests.
// So if a test does a session_reload, it will merge the odoo global of that test
// into the session, and will alter every subsequent test of the suite.
// Obviously, we don't want that, ever.
import { session as sessionInfo } from "@web/session";
const initialSessionInfo = Object.assign({}, sessionInfo);
import Session from "@web/legacy/js/core/session";
import { patch } from "@web/core/utils/patch";
patch(Session.prototype, {
async session_reload() {
for (const key in sessionInfo) {
delete sessionInfo[key];
}
for (const key in initialSessionInfo) {
sessionInfo[key] = initialSessionInfo[key];
}
return await super.session_reload(...arguments);
},
});
@@ -1,5 +1,6 @@
/** @odoo-module **/
import { strftimeToLuxonFormat } from "@web/core/l10n/dates";
import { localization } from "@web/core/l10n/localization";
import time from "@web/legacy/js/core/time";
@@ -149,8 +150,8 @@ QUnit.module('core', {}, function () {
assert.expect(4);
const originalParameters = Object.assign({}, localization);
Object.assign(localization, {
dateFormat: '%m/%d/%Y',
timeFormat: '%H:%M:%S',
dateFormat: strftimeToLuxonFormat('%m/%d/%Y'),
timeFormat: strftimeToLuxonFormat('%H:%M:%S'),
});
assert.strictEqual(time.getLangDateFormat(), "MM/DD/YYYY");
assert.strictEqual(time.getLangDateFormatWoZero(), "M/D/YYYY");
@@ -2,11 +2,9 @@
import Dialog from "@web/legacy/js/core/dialog";
import Widget from "@web/legacy/js/core/widget";
import session from "web.session";
import { patchWithCleanup } from "@web/../tests/helpers/utils";
import testUtils from "@web/../tests/legacy/helpers/test_utils";
import { renderToString } from "@web/core/utils/render";
import env from "@web/legacy/js/common_env";
import { makeLegacyRPC } from "@web/legacy/utils";
QUnit.module('core', {}, function () {
@@ -403,18 +401,17 @@ QUnit.module('core', {}, function () {
QUnit.test("calling _rpc on destroyed widgets", async function (assert) {
assert.expect(3);
const rpc = makeLegacyRPC(() => {
def = testUtils.makeTestPromise();
def.abort = def.reject;
return def;
});
var def;
var parent = new Widget();
patchWithCleanup(session, {
rpc: () => {
def = testUtils.makeTestPromise();
def.abort = def.reject;
return def;
},
});
testUtils.mock.intercept(parent, 'call_service', function ({ data }) {
if (data.service === "ajax" && data.method === "rpc") {
data.callback(env.services.ajax.rpc(...data.args));
data.callback(rpc(...data.args));
}
});
var widget = new Widget(parent);
@@ -1,8 +1,7 @@
/** @odoo-module **/
import Bus from "@web/legacy/js/core/bus";
import session from "web.session";
import { makeTestEnvServices } from "@web/../tests/legacy/helpers/test_services";
import { buildQuery } from "@web/legacy/js/core/rpc";
import { templates, setLoadXmlDefaultApp } from "@web/core/assets";
import { renderToString } from "@web/core/utils/render";
const { App, Component } = owl;
@@ -25,29 +24,31 @@
setLoadXmlDefaultApp(app);
}
function rpc(route, params, options) {
if (providedRPC) {
return providedRPC(route, params, options);
}
throw new Error(`No method to perform RPC`);
}
const defaultEnv = {
browser: Object.assign({
setTimeout: window.setTimeout.bind(window),
clearTimeout: window.clearTimeout.bind(window),
setInterval: window.setInterval.bind(window),
clearInterval: window.clearInterval.bind(window),
requestAnimationFrame: window.requestAnimationFrame.bind(window),
Date: window.Date,
fetch: (window.fetch || (() => { })).bind(window),
}, env.browser),
bus: env.bus || new Bus(),
debug: env.debug || false,
services: makeTestEnvServices(env),
session: Object.assign({
rpc(route, params, options) {
if (providedRPC) {
return providedRPC(route, params, options);
}
throw new Error(`No method to perform RPC`);
services: {
getCookie() {},
httpRequest(/* route, params = {}, readMethod = 'json' */) {
return Promise.resolve('');
},
url: session.url,
getTZOffset: (() => 0),
}, env.session),
hotkey: { add: () => () => {} }, // fake service
notification: { notify() {} },
ajax: { rpc },
rpc(params, options) {
const query = buildQuery(params);
return rpc(query.route, query.params, options);
},
ui: { activeElement: document }, // fake service
...env.services,
},
};
return Object.assign(env, defaultEnv);
}
@@ -1,38 +0,0 @@
/** @odoo-module */
import { buildQuery } from '@web/legacy/js/core/rpc';
const testEnvServices = {
getCookie() {},
httpRequest(/* route, params = {}, readMethod = 'json' */) {
return Promise.resolve('');
},
hotkey: { add: () => () => {} }, // fake service
notification: { notify() {} },
};
/**
* Creates services for the test environment. object
*
* @param {Object} [env]
* @returns {Object}
*/
function makeTestEnvServices(env) {
return Object.assign({}, testEnvServices, {
ajax: {
rpc() {
return env.session.rpc(...arguments); // Compatibility Legacy Widgets
},
},
rpc(params, options) {
const query = buildQuery(params);
return env.session.rpc(query.route, query.params, options);
},
ui: { activeElement: document }, // fake service
}, env.services);
}
export {
makeTestEnvServices,
testEnvServices,
};
@@ -0,0 +1,16 @@
/** @odoo-module */
import { localization } from "@web/core/l10n/localization";
Object.assign(localization, {
dateFormat: "MM/dd/yyyy",
timeFormat: "HH:mm:ss",
dateTimeFormat: "MM/dd/yyyy HH:mm:ss",
decimalPoint: ".",
direction: "ltr",
grouping: [],
multiLang: false,
thousandsSep: ",",
weekStart: 7,
code: "en",
});
+1 -38
View File
@@ -1,8 +1,6 @@
/** @odoo-module **/
import { _t } from "@web/legacy/js/core/translation";
import LegacyBus from "@web/legacy/js/core/bus";
import session from "web.session";
import { assets, templates } from "@web/core/assets";
import { browser, makeRAMLocalStorage } from "@web/core/browser/browser";
import { nextTick, patchTimeZone, patchWithCleanup } from "@web/../tests/helpers/utils";
@@ -18,40 +16,6 @@ transitionConfig.disabled = true;
import { patch } from "@web/core/utils/patch";
import { App, EventBus, whenReady } from "@odoo/owl";
import { currencies } from "@web/core/currency";
import "./helpers/session";
function stringifyObjectValues(obj, properties) {
let res = "";
for (const dotted of properties) {
const keys = dotted.split(".");
let val = obj;
for (const k of keys) {
val = val[k];
}
res += JSON.stringify(val);
}
return res;
}
function checkGlobalObjectsIntegrity() {
const objects = [
[session, ["user_context", "currencies"]],
[_t, ["database.multi_lang", "database.parameters"]],
];
const initials = objects.map((obj) => stringifyObjectValues(obj[0], obj[1]));
registerCleanup((infos) => {
const finals = objects.map((obj) => stringifyObjectValues(obj[0], obj[1]));
for (const index in initials) {
if (initials[index] !== finals[index]) {
const [, /* global */ keys] = objects[index];
throw new Error(
`The keys "${keys}" of some global objects (usually session or _t) may have been polluted by the test "${infos.testName}" in module "${infos.moduleName}". Initial: ${initials[index]}. Final: ${finals[index]}.`
);
}
}
});
}
function forceLocaleAndTimezoneWithCleanup() {
const originalLocale = luxon.Settings.defaultLocale;
@@ -385,7 +349,6 @@ export async function setupTests() {
// }
QUnit.testStart(() => {
checkGlobalObjectsIntegrity();
prepareRegistriesWithCleanup();
forceLocaleAndTimezoneWithCleanup();
cleanLoadedLanguages();
@@ -398,7 +361,7 @@ export async function setupTests() {
patchOwlApp();
});
await Promise.all([whenReady(), session.is_bound]);
await whenReady();
// alt attribute causes issues with scroll tests. Indeed, alt is
// displayed between the time we scroll programatically and the time
-2
View File
@@ -103,9 +103,7 @@ Odoo Web Editor widget.
'web/static/src/legacy/js/core/mixins.js',
'web/static/src/legacy/js/core/rpc.js',
'web/static/src/legacy/js/core/service_mixins.js',
'web/static/src/legacy/js/core/session.js',
'web/static/src/legacy/js/core/time.js',
'web/static/src/legacy/js/core/translation.js',
'web/static/src/legacy/js/core/utils.js',
'web/static/src/legacy/js/core/widget.js',
'web/static/src/legacy/js/services/core.js',
@@ -3028,10 +3028,6 @@ export class Wysiwyg extends Component {
const payload = ev.data;
if (evType === 'call_service') {
this._callService(payload);
} else if (evType === 'get_session') {
if (payload.callback) {
payload.callback(this.env.session);
}
}
}
_callService(payload) {
@@ -215,10 +215,6 @@ function getWysiwygIframeContent(params) {
${assets.jsContents.join('\n')}
<script type="text/javascript">
odoo.define('web.session', [], function () {
return window.top.odoo.__DEBUG__.services['web.session'];
});
odoo.define('root.widget', ['@web/legacy/js/core/widget'], function (require) {
'use strict';
var Widget = require('@web/legacy/js/core/widget')[Symbol.for("default")];
@@ -3,7 +3,7 @@
import { loadJS } from "@web/core/assets";
import { _t } from "@web/core/l10n/translation";
import { Markup } from '@web/legacy/js/core/utils';
import session from 'web.session';
import { session } from "@web/session";
import publicRootData from '@web/legacy/js/public/public_root';
import "@website/libs/zoomodoo/zoomodoo";
import { pick } from "@web/core/utils/objects";
@@ -2,7 +2,7 @@
import time from "@web/legacy/js/core/time";
import {ReCaptcha} from "@google_recaptcha/js/recaptcha";
import session from "web.session";
import { session } from "@web/session";
import ajax from "@web/legacy/js/core/ajax";
import publicWidget from "@web/legacy/js/public/public_widget";
import dom from "@web/legacy/js/core/dom";
+2 -7
View File
@@ -1,18 +1,13 @@
/** @odoo-module **/
import session from "web.session";
import wTourUtils from "@website/js/tours/tour_utils";
import { Wysiwyg } from "@web_editor/js/wysiwyg/wysiwyg";
var domReady = new Promise(function (resolve) {
$(resolve);
});
var ready = Promise.all([domReady, session.is_bound]);
import { whenReady } from "@odoo/owl";
wTourUtils.registerWebsitePreviewTour('rte_translator', {
test: true,
url: '/',
wait_for: ready,
wait_for: whenReady(),
}, () => [{
content: "click language dropdown",
trigger: 'iframe .js_language_selector .dropdown-toggle',
@@ -1,7 +1,7 @@
/** @odoo-module **/
import publicWidget from "@web/legacy/js/public/public_widget";
import session from "web.session";
import { session } from "@web/session";
import { _t } from "@web/core/l10n/translation";
import { renderToElement } from "@web/core/utils/render";
@@ -7,7 +7,7 @@ import {setCookie} from "@web/legacy/js/core/cookie_utils";
import { loadWysiwygFromTextarea } from "@web_editor/js/frontend/loadWysiwygFromTextarea";
import publicWidget from "@web/legacy/js/public/public_widget";
import { Markup } from '@web/legacy/js/core/utils';
import session from "web.session";
import { session } from "@web/session";
import { escape } from "@web/core/utils/strings";
import { _t } from "@web/core/l10n/translation";
import { renderToElement } from "@web/core/utils/render";
-3
View File
@@ -206,9 +206,7 @@ Featuring
'web/static/src/legacy/js/core/mixins.js',
'web/static/src/legacy/js/core/rpc.js',
'web/static/src/legacy/js/core/service_mixins.js',
'web/static/src/legacy/js/core/session.js',
'web/static/src/legacy/js/core/time.js',
'web/static/src/legacy/js/core/translation.js',
'web/static/src/legacy/js/core/utils.js',
'web/static/src/legacy/js/core/widget.js',
'web/static/src/legacy/js/services/core.js',
@@ -218,7 +216,6 @@ Featuring
'web/static/src/core/**/*.js',
'web/static/src/env.js',
'web/static/src/libs/pdfjs.js',
'web/static/src/legacy/js/services/session.js',
('remove', 'web/static/src/core/emoji_picker/emoji_data.js'),
('include', 'web._assets_helpers'),
@@ -6,8 +6,7 @@
import { _t } from "@web/core/l10n/translation";
import { renderToElement } from "@web/core/utils/render";
import { Markup } from "@web/legacy/js/core/utils";
import session from 'web.session';
import { session } from "@web/session";
import { Quiz } from '@website_slides/js/slides_course_quiz';
import { SlideCoursePage } from '@website_slides/js/slides_course_page';
import { unhideConditionalElements } from '@website/js/content/inject_dom';
@@ -1,7 +1,7 @@
/** @odoo-module **/
import publicWidget from '@web/legacy/js/public/public_widget';
import session from 'web.session';
import { session } from "@web/session";
import { renderToElement } from "@web/core/utils/render";
/**
@@ -3,7 +3,7 @@
import publicWidget from '@web/legacy/js/public/public_widget';
import Dialog from '@web/legacy/js/core/dialog';
import { renderToElement } from "@web/core/utils/render";
import session from 'web.session';
import { session } from "@web/session";
import { Markup } from "@web/legacy/js/core/utils";
import CourseJoin from '@website_slides/js/slides_course_join';
import QuestionFormWidget from '@website_slides/js/slides_course_quiz_question_form';