flectra.define('web.Session', function (require) { "use strict"; var ajax = require('web.ajax'); var concurrency = require('web.concurrency'); var core = require('web.core'); var mixins = require('web.mixins'); var utils = require('web.utils'); var _t = core._t; var qweb = core.qweb; // To do: refactor session. Session accomplishes several concerns (rpc, // configuration, currencies (wtf?), user permissions...). They should be // clarified and separated. var Session = core.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: * "override_session": Default to false. If true, the current session object will not try to re-use a previously created session id stored in a cookie. * "session_id": Default to null. If specified, the specified session_id will be used by this session object. Specifying this option automatically implies that the option "override_session" is set to true. */ init: function (parent, origin, options) { mixins.EventDispatcherMixin.init.call(this, parent); options = options || {}; this.module_list = (options.modules && options.modules.slice()) || (window.flectra._modules && window.flectra._modules.slice()) || []; this.server = null; this.session_id = options.session_id || null; this.override_session = options.override_session || !!options.session_id || false; this.avoid_recursion = false; this.use_cors = options.use_cors || false; this.setup(origin); var debug_param = $.deparam($.param.querystring()).debug; this.debug = (debug_param !== undefined ? debug_param || 1 : false); // 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.qweb_mutex = new concurrency.Mutex(); this.currencies = {}; this._groups_def = {}; }, setup: function (origin, options) { // must be able to customize server var window_origin = location.protocol + "//" + location.host; origin = origin ? origin.replace( /\/+$/, '') : window_origin; if (!_.isUndefined(this.origin) && 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 this.origin_server = this.origin === window_origin; options = options || {}; if ('use_cors' in options) { this.use_cors = options.use_cors; } }, /** * Setup a session */ session_bind: function (origin) { var self = this; this.setup(origin); qweb.default_dict._s = this.origin; this.uid = null; this.username = null; this.user_context= {}; this.db = null; this.module_loaded = {}; _(this.module_list).each(function (mod) { self.module_loaded[mod] = true; }); this.active_id = null; return this.session_init(); }, /** * Init a session, reloads from cookie, if it exists */ session_init: function () { var self = this; var def = this.session_reload(); if (this.is_frontend) { return def.then(function () { return self.load_translations(); }); } return def.then(function () { var modules = self.module_list.join(','); var deferred = self.load_qweb(modules); if (self.session_is_valid()) { return deferred.then(function () { return self.load_modules(); }); } return $.when( deferred, self.rpc('/web/webclient/bootstrap_translations', {mods: self.module_list}) .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 $.when(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 $.Deferred().reject(); } delete result.session_id; _.extend(self, result); }); }, session_logout: function () { $.bbq.removeState(); return this.rpc("/web/session/destroy", {}); }, user_has_group: function (group) { if (!this.uid) { return $.when(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 0) qs = "?" + qs; var prefix = _.any(['http://', 'https://', '//'], function (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(date).getTimezoneOffset(); }, }); return Session; });