Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ addon | version | maintainers | summary
[scheduler_error_mailer](scheduler_error_mailer/) | 18.0.1.0.0 | | Scheduler Error Mailer
[sentry](sentry/) | 18.0.1.0.4 | <a href='https://github.com/barsi'><img src='https://github.com/barsi.png' width='32' height='32' style='border-radius:50%;' alt='barsi'/></a> <a href='https://github.com/naglis'><img src='https://github.com/naglis.png' width='32' height='32' style='border-radius:50%;' alt='naglis'/></a> <a href='https://github.com/versada'><img src='https://github.com/versada.png' width='32' height='32' style='border-radius:50%;' alt='versada'/></a> <a href='https://github.com/moylop260'><img src='https://github.com/moylop260.png' width='32' height='32' style='border-radius:50%;' alt='moylop260'/></a> <a href='https://github.com/fernandahf'><img src='https://github.com/fernandahf.png' width='32' height='32' style='border-radius:50%;' alt='fernandahf'/></a> | Report Odoo errors to Sentry
[sequence_python](sequence_python/) | 18.0.1.0.0 | | Calculate a sequence number from a Python expression
[session_db](session_db/) | 18.0.1.0.1 | <a href='https://github.com/sbidoul'><img src='https://github.com/sbidoul.png' width='32' height='32' style='border-radius:50%;' alt='sbidoul'/></a> | Store sessions in DB
[session_db](session_db/) | 18.0.1.0.2 | <a href='https://github.com/sbidoul'><img src='https://github.com/sbidoul.png' width='32' height='32' style='border-radius:50%;' alt='sbidoul'/></a> | Store sessions in DB
[test_auditlog](test_auditlog/) | 18.0.1.0.3 | | Additional unit tests for Audit Log based on accounting models
[test_base_time_window](test_base_time_window/) | 18.0.1.0.0 | | Test Base model to handle time windows
[tracking_manager](tracking_manager/) | 18.0.1.1.0 | <a href='https://github.com/Kev-Roche'><img src='https://github.com/Kev-Roche.png' width='32' height='32' style='border-radius:50%;' alt='Kev-Roche'/></a> <a href='https://github.com/sebastienbeau'><img src='https://github.com/sebastienbeau.png' width='32' height='32' style='border-radius:50%;' alt='sebastienbeau'/></a> | This module tracks all fields of a model, including one2many and many2many ones.
Expand Down
15 changes: 13 additions & 2 deletions session_db/README.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

====================
Store sessions in DB
====================
Expand All @@ -7,13 +11,13 @@ Store sessions in DB
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:7558240596b423e92065ebf70859ac382972bca78db62368b1d0e7f06cc2a266
!! source digest: sha256:b732da96d2a87ff5a4503e576f75338a858701e8c6b32619d8eba6fcd263332d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github
Expand Down Expand Up @@ -67,6 +71,13 @@ Authors
* Odoo SA
* ACSONE SA/NV

Contributors
------------

- Nicolas Seinlet
- Stéphane Bidoul <stephane.bidoul@acsone.eu> (https://acsone.eu)
- Dennis Sluijk <d.sluijk@onestein.nl> (https://onestein.nl)

Maintainers
-----------

Expand Down
2 changes: 1 addition & 1 deletion session_db/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Store sessions in DB",
"version": "18.0.1.0.1",
"version": "18.0.1.0.2",
"author": "Odoo SA,ACSONE SA/NV,Odoo Community Association (OCA)",
"license": "LGPL-3",
"website": "https://github.com/OCA/server-tools",
Expand Down
42 changes: 42 additions & 0 deletions session_db/pg_session_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,48 @@ def vacuum(self, max_lifetime=http.SESSION_LIFETIME):
(f"{max_lifetime} seconds",),
)

@with_lock
@with_cursor
def get_missing_session_identifiers(self, identifiers: list[str]) -> set[str]:
"""
:param identifiers: session identifiers whose file existence must be checked
identifiers are a part session sid (first 42 chars)
:type identifiers: iterable
:return: the identifiers which are not present on the filesystem
:rtype: set

Note 1:
Working with identifiers 42 characters long means that
we don't have to work with the entire sid session,
while maintaining sufficient entropy to avoid collisions.
See details in ``generate_key``.

Note 2:
Scans the session store for inactive (GC'd) sessions.
Performance is acceptable for an infrequent background job.
"""
missing_identifiers = set()
for identifier in identifiers:
self._cr.execute(
"SELECT sid FROM http_sessions WHERE sid LIKE %s||'%%' LIMIT 1",
(identifier,),
)
if self._cr.rowcount == 0:
missing_identifiers.add(identifier)
return missing_identifiers

@with_lock
@with_cursor
def delete_from_identifiers(self, identifiers: list[str]) -> None:
for identifier in identifiers:
if not http._session_identifier_re.match(
identifier
) and not sessions._sha1_re.match(identifier):
continue
self._cr.execute(
"DELETE FROM http_sessions WHERE sid LIKE %s||'%%'", (identifier,)
)


_original_session_store = http.root.__class__.session_store

Expand Down
3 changes: 3 additions & 0 deletions session_db/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Nicolas Seinlet
- Stéphane Bidoul \<<stephane.bidoul@acsone.eu>\> (<https://acsone.eu>)
- Dennis Sluijk \<<d.sluijk@onestein.nl>\> (<https://onestein.nl>)
37 changes: 26 additions & 11 deletions session_db/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Store sessions in DB</title>
<title>README.rst</title>
<style type="text/css">

/*
Expand Down Expand Up @@ -360,16 +360,21 @@
</style>
</head>
<body>
<div class="document" id="store-sessions-in-db">
<h1 class="title">Store sessions in DB</h1>
<div class="document">


<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="store-sessions-in-db">
<h1>Store sessions in DB</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:7558240596b423e92065ebf70859ac382972bca78db62368b1d0e7f06cc2a266
!! source digest: sha256:b732da96d2a87ff5a4503e576f75338a858701e8c6b32619d8eba6fcd263332d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/server-tools/tree/18.0/session_db"><img alt="OCA/server-tools" src="https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/server-tools-18-0/server-tools-18-0-session_db"><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/server-tools&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<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/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/license-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/server-tools/tree/18.0/session_db"><img alt="OCA/server-tools" src="https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/server-tools-18-0/server-tools-18-0-session_db"><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/server-tools&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>Store sessions in a database instead of the filesystem. This simplifies
the configuration of horizontally scalable deployments, by avoiding the
need for a distributed filesystem to store the Odoo sessions.</p>
Expand All @@ -380,38 +385,47 @@ <h1 class="title">Store sessions in DB</h1>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-5">Maintainers</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
<p>Set this module in the server wide modules.</p>
<p>Set a <tt class="docutils literal">SESSION_DB_URI</tt> environment variable as a full postgresql
connection string, like <tt class="docutils literal"><span class="pre">postgres://user:passwd&#64;server/db</span></tt> or <tt class="docutils literal">db</tt>.</p>
<p>It is recommended to use a dedicated database for this module, and
possibly a dedicated postgres user for additional security.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<h2><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h2>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/server-tools/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/server-tools/issues/new?body=module:%20session_db%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<h2><a class="toc-backref" href="#toc-entry-3">Credits</a></h2>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<h3><a class="toc-backref" href="#toc-entry-4">Authors</a></h3>
<ul class="simple">
<li>Odoo SA</li>
<li>ACSONE SA/NV</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-5">Contributors</a></h3>
<ul class="simple">
<li>Nicolas Seinlet</li>
<li>Stéphane Bidoul &lt;<a class="reference external" href="mailto:stephane.bidoul&#64;acsone.eu">stephane.bidoul&#64;acsone.eu</a>&gt; (<a class="reference external" href="https://acsone.eu">https://acsone.eu</a>)</li>
<li>Dennis Sluijk &lt;<a class="reference external" href="mailto:d.sluijk&#64;onestein.nl">d.sluijk&#64;onestein.nl</a>&gt; (<a class="reference external" href="https://onestein.nl">https://onestein.nl</a>)</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
<h3><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h3>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
Expand All @@ -426,5 +440,6 @@ <h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
</div>
</div>
</div>
</div>
</body>
</html>
45 changes: 45 additions & 0 deletions session_db/tests/test_pg_session_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,48 @@ def test_make_postgres_uri(self):
assert "postgres://test:PASSWORD@localhost:5432/test" == _make_postgres_uri(
**connection_info
)

def test_missing_session_identifiers(self):
session = self.session_store.new()
self.session_store.save(session)
missing_identifiers = self.session_store.get_missing_session_identifiers(
[session.sid]
)
self.assertEqual(missing_identifiers, set())
self.session_store.delete_from_identifiers([session.sid])
missing_identifiers = self.session_store.get_missing_session_identifiers(
[session.sid]
)
self.assertEqual(missing_identifiers, {session.sid})

def test_revoke_res_device_log(self):
# Truncate the session table to ensure that the session store is empty before
# starting the test
self.session_store._cr.execute("TRUNCATE TABLE http_sessions")

# Create a session and save it to the session store
session = self.session_store.new()
self.session_store.save(session)

# Patch odoo.http.root.session_store to use the test session store
with mock.patch("odoo.http.root.session_store", self.session_store):
# Create a res.device.log entry for the session
log = self.env["res.device"].create(
{
"session_identifier": session.sid,
"user_id": self.ref("base.user_demo"),
"first_activity": "2020-01-01 00:00:00",
"last_activity": "2020-01-01 00:00:00",
}
)
log._revoke()

# The session shouldn't exist anymore in the session store
missing_identifiers = self.session_store.get_missing_session_identifiers(
[session.sid]
)
self.assertEqual(missing_identifiers, {session.sid})

# This will return a new session if it can't fetch one
session_in_store = self.session_store.get(session.sid)
self.assertNotEqual(session_in_store.sid, session.sid)