Skip to content

Commit 404a6a8

Browse files
[MIG] web_session_auto_close: Migration to 19.0
1 parent 69c3ebf commit 404a6a8

8 files changed

Lines changed: 160 additions & 73 deletions

File tree

web_session_auto_close/README.rst

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ Web Session Auto Close
2121
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
2222
:alt: License: AGPL-3
2323
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
24-
:target: https://github.com/OCA/web/tree/18.0/web_session_auto_close
24+
:target: https://github.com/OCA/web/tree/19.0/web_session_auto_close
2525
:alt: OCA/web
2626
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
27-
:target: https://translation.odoo-community.org/projects/web-18-0/web-18-0-web_session_auto_close
27+
:target: https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_session_auto_close
2828
:alt: Translate me on Weblate
2929
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
30-
:target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=18.0
30+
:target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=19.0
3131
:alt: Try me on Runboat
3232

3333
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -53,7 +53,7 @@ Bug Tracker
5353
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web/issues>`_.
5454
In case of trouble, please check there if your issue has already been reported.
5555
If you spotted it first, help us to smash it by providing a detailed and welcomed
56-
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_session_auto_close%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
56+
`feedback <https://github.com/OCA/web/issues/new?body=module:%20web_session_auto_close%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
5757

5858
Do not contact contributors directly about support or help with technical issues.
5959

@@ -70,6 +70,9 @@ Contributors
7070

7171
- Laurent Stukkens <laurent.stukkens@acsone.eu> (https://www.acsone.eu)
7272
- Souheil Bejaoui <souheil.bejaoui@acsone.eu> (https://www.acsone.eu)
73+
- `Komit <https://komit-consulting.com>`__:
74+
75+
- Vang Nguyen Phu
7376

7477
Maintainers
7578
-----------
@@ -84,6 +87,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
8487
mission is to support the collaborative development of Odoo features and
8588
promote its widespread use.
8689

87-
This module is part of the `OCA/web <https://github.com/OCA/web/tree/18.0/web_session_auto_close>`_ project on GitHub.
90+
This module is part of the `OCA/web <https://github.com/OCA/web/tree/19.0/web_session_auto_close>`_ project on GitHub.
8891

8992
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

web_session_auto_close/__manifest__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"name": "Web Session Auto Close",
66
"summary": """Automatically logs out inactive users based on a configurable
77
timeout.""",
8-
"version": "18.0.1.0.1",
8+
"version": "19.0.1.0.1",
99
"license": "AGPL-3",
1010
"author": "ACSONE SA/NV, Odoo Community Association (OCA)",
1111
"website": "https://github.com/OCA/web",

web_session_auto_close/controllers/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
class WebSessionAutoCloseController(http.Controller):
9-
@http.route("/web/session/get_timeout", type="json", auth="user")
9+
@http.route("/web/session/get_timeout", type="jsonrpc", auth="user")
1010
def get_session_timeout(self):
1111
timeout_sec = (
1212
request.env["ir.config_parameter"]

web_session_auto_close/readme/CONTRIBUTORS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
(<https://www.acsone.eu>)
33
- Souheil Bejaoui \<<souheil.bejaoui@acsone.eu>\>
44
(<https://www.acsone.eu>)
5+
- [Komit](https://komit-consulting.com):
6+
- Vang Nguyen Phu

web_session_auto_close/static/description/index.html

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ <h1>Web Session Auto Close</h1>
374374
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
375375
!! source digest: sha256:8244d213321585d6b7f6632ffc7e98fa6fb6902f1ac2e3e883efb596bbf55572
376376
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
377-
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/web/tree/18.0/web_session_auto_close"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/web-18-0/web-18-0-web_session_auto_close"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/web&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
377+
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/web/tree/19.0/web_session_auto_close"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_session_auto_close"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/web&amp;target_branch=19.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
378378
<p>This module automatically closes inactive user sessions based on a
379379
configurable timeout. If no activity is detected within the set
380380
duration, the session is destroyed, and the page reloads.</p>
@@ -401,7 +401,7 @@ <h2><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h2>
401401
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
402402
In case of trouble, please check there if your issue has already been reported.
403403
If you spotted it first, help us to smash it by providing a detailed and welcomed
404-
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_session_auto_close%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
404+
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_session_auto_close%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
405405
<p>Do not contact contributors directly about support or help with technical issues.</p>
406406
</div>
407407
<div class="section" id="credits">
@@ -417,6 +417,10 @@ <h3><a class="toc-backref" href="#toc-entry-5">Contributors</a></h3>
417417
<ul class="simple">
418418
<li>Laurent Stukkens &lt;<a class="reference external" href="mailto:laurent.stukkens&#64;acsone.eu">laurent.stukkens&#64;acsone.eu</a>&gt; (<a class="reference external" href="https://www.acsone.eu">https://www.acsone.eu</a>)</li>
419419
<li>Souheil Bejaoui &lt;<a class="reference external" href="mailto:souheil.bejaoui&#64;acsone.eu">souheil.bejaoui&#64;acsone.eu</a>&gt; (<a class="reference external" href="https://www.acsone.eu">https://www.acsone.eu</a>)</li>
420+
<li><a class="reference external" href="https://komit-consulting.com">Komit</a>:<ul>
421+
<li>Vang Nguyen Phu</li>
422+
</ul>
423+
</li>
420424
</ul>
421425
</div>
422426
<div class="section" id="maintainers">
@@ -428,7 +432,7 @@ <h3><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h3>
428432
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
429433
mission is to support the collaborative development of Odoo features and
430434
promote its widespread use.</p>
431-
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/18.0/web_session_auto_close">OCA/web</a> project on GitHub.</p>
435+
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/web/tree/19.0/web_session_auto_close">OCA/web</a> project on GitHub.</p>
432436
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
433437
</div>
434438
</div>
Lines changed: 118 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,141 @@
1-
/** @odoo-module **/
2-
31
/* Copyright 2025 ACSONE SA/NV
42
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */
53

64
import {rpc} from "@web/core/network/rpc";
75
import {session} from "@web/session";
86

97
// Default session timeout in ms (will be updated from server settings)
10-
let SESSION_TIMEOUT = 600000;
8+
const SESSION_TIMEOUT = 600000;
119

12-
/**
13-
* Get the last recorded user activity timestamp from localStorage
14-
* if no record is found, returns the current timestamp
15-
*/
16-
function getLastActivityTime() {
17-
return (
18-
parseInt(globalThis.window.localStorage.getItem("lastActivityTime"), 10) ||
19-
Date.now()
20-
);
21-
}
10+
export class SessionAutoCloseService {
11+
constructor() {
12+
this.sessionTimeout = SESSION_TIMEOUT;
13+
this._checkIntervalId = null;
14+
this._boundCheckInactivity = () => this.checkInactivity();
15+
this._boundHandleUserActivity = () => this.handleUserActivity();
16+
}
2217

23-
/**
24-
* Set the last activity timestamp in localStorage
25-
* this is called whenever user interaction is detected
26-
*/
27-
function updateActivityTime() {
28-
const now = Date.now();
29-
globalThis.window.localStorage.setItem("lastActivityTime", now);
30-
}
18+
/**
19+
* Storage key for last activity timestamp in localStorage.
20+
* @returns {String}
21+
*/
22+
getActivityStorageKey() {
23+
return "lastActivityTime";
24+
}
3125

32-
/**
33-
* Destroy the session
34-
* removes the last activity record and reloads the page
35-
*/
36-
function closeSession() {
37-
rpc("/web/session/destroy", {}).then(() => {
38-
globalThis.window.localStorage.removeItem("lastActivityTime");
26+
/**
27+
* Get the last recorded user activity timestamp from localStorage
28+
* if no record is found, returns the current timestamp
29+
*/
30+
getLastActivityTime() {
31+
const key = this.getActivityStorageKey();
32+
const value = globalThis.window.localStorage.getItem(key);
33+
return parseInt(value, 10) || Date.now();
34+
}
35+
36+
/**
37+
* Set the last activity timestamp in localStorage
38+
* this is called whenever user interaction is detected
39+
*/
40+
updateActivityTime() {
41+
const key = this.getActivityStorageKey();
42+
globalThis.window.localStorage.setItem(key, String(Date.now()));
43+
}
44+
45+
/**
46+
* Destroy the session
47+
* removes the last activity record and reloads the page
48+
*/
49+
async closeSession() {
50+
await rpc("/web/session/destroy", {});
51+
const key = this.getActivityStorageKey();
52+
globalThis.window.localStorage.removeItem(key);
3953
globalThis.window.location.reload();
40-
});
41-
}
54+
}
4255

43-
/**
44-
* Checks for user inactivity and closes the session if the timeout is exceeded
45-
*/
46-
function checkInactivity() {
47-
const now = Date.now();
48-
const lastActivityTime = getLastActivityTime();
49-
if (now - lastActivityTime >= SESSION_TIMEOUT) {
50-
closeSession();
56+
/**
57+
* Handler for activity events; by default just updates the activity time.
58+
*/
59+
handleUserActivity() {
60+
this.updateActivityTime();
5161
}
52-
}
5362

54-
/**
55-
* Init the session auto-close mechanism
56-
* attaches event listeners to detect user activity and sets periodic
57-
inactivity checks
58-
*/
59-
function startSessionAutoClose() {
60-
if (!session) {
61-
return;
63+
/**
64+
* Checks for user inactivity and closes the session if the timeout is exceeded
65+
*/
66+
checkInactivity() {
67+
const now = Date.now();
68+
const lastActivityTime = this.getLastActivityTime();
69+
if (now - lastActivityTime >= this.sessionTimeout) {
70+
this.closeSession();
71+
}
6272
}
6373

64-
// Immediately check inactivity if a last activity timestamp exists
65-
if (globalThis.window.localStorage.getItem("lastActivityTime")) {
66-
checkInactivity();
74+
/**
75+
* Whether the service should start (e.g. only when session exists).
76+
* @returns {Boolean}
77+
*/
78+
shouldStart() {
79+
return Boolean(session);
6780
}
6881

69-
function handleUserActivity() {
70-
updateActivityTime();
82+
/**
83+
* Fetch timeout from server.
84+
* @returns {Promise<number>} Timeout in ms
85+
*/
86+
async getTimeout() {
87+
const timeout = await rpc("/web/session/get_timeout", {});
88+
return parseInt(timeout, 10) || SESSION_TIMEOUT;
7189
}
7290

73-
// Listen for user interactions to reset the activity timer
74-
globalThis.window.addEventListener("mousemove", handleUserActivity);
75-
globalThis.window.addEventListener("keydown", handleUserActivity);
91+
/**
92+
* Event bindings for activity detection.
93+
* @returns {{ target: EventTarget, events: string[] }}
94+
*/
95+
getActivityEvents() {
96+
return {
97+
target: globalThis.window,
98+
events: ["mousemove", "keydown"],
99+
};
100+
}
76101

77-
// Set the initial activity time and start the periodic inactivity check
78-
updateActivityTime();
79-
globalThis.setInterval(checkInactivity, SESSION_TIMEOUT / 2);
102+
/**
103+
* Attach activity listeners and start the periodic inactivity check.
104+
*/
105+
_startMonitoring() {
106+
const key = this.getActivityStorageKey();
107+
if (globalThis.window.localStorage.getItem(key)) {
108+
this.checkInactivity();
109+
}
110+
111+
const {target, events} = this.getActivityEvents();
112+
for (const eventName of events) {
113+
target.addEventListener(eventName, this._boundHandleUserActivity);
114+
}
115+
116+
this.updateActivityTime();
117+
const intervalMs = this.sessionTimeout / 2;
118+
this._checkIntervalId = globalThis.setInterval(
119+
this._boundCheckInactivity,
120+
intervalMs
121+
);
122+
}
123+
124+
/**
125+
* Start the service: load timeout, then start monitoring if shouldStart().
126+
* Call once after construction.
127+
*/
128+
async start() {
129+
this.sessionTimeout = await this.getTimeout();
130+
if (!this.shouldStart()) {
131+
return;
132+
}
133+
this._startMonitoring();
134+
}
80135
}
81136

82-
// Fetch the session timeout value from Odoo settings and then start the session monitoring
83-
rpc("/web/session/get_timeout", {}).then((timeout) => {
84-
SESSION_TIMEOUT = parseInt(timeout, 10) || SESSION_TIMEOUT;
85-
startSessionAutoClose();
86-
});
137+
/**
138+
* Default service instance, started on load.
139+
*/
140+
const service = new SessionAutoCloseService();
141+
service.start();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import test_get_timeout_controller
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from odoo.tests import tagged
2+
3+
from odoo.addons.base.tests.common import HttpCaseWithUserDemo
4+
5+
6+
@tagged("-at_install", "post_install")
7+
class TestGetTimeoutController(HttpCaseWithUserDemo):
8+
@classmethod
9+
def setUpClass(cls):
10+
super().setUpClass()
11+
cls.env["ir.config_parameter"].sudo().set_param(
12+
"web_session_auto_close.timeout", 123
13+
)
14+
cls.session = cls.authenticate(cls, "demo", "demo")
15+
16+
def setUp(self):
17+
super().setUp()
18+
self.opener.cookies["session_id"] = self.session.sid
19+
20+
def test_get_timeout_returns_ms(self):
21+
timeout = self.make_jsonrpc_request("/web/session/get_timeout", {})
22+
self.assertEqual(timeout, 123 * 1000)

0 commit comments

Comments
 (0)