diff --git a/auditlog/README.rst b/auditlog/README.rst
index 70d38a77d..79a23a257 100644
--- a/auditlog/README.rst
+++ b/auditlog/README.rst
@@ -1,5 +1,10 @@
-Track user operation on data models
-===================================
+.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+=================================
+Audit Log - Track user operations
+=================================
This module allows the administrator to log user operations performed on data
models such as ``create``, ``read``, ``write`` and ``delete``.
@@ -11,12 +16,14 @@ Go to `Reporting / Audit / Rules` to subscribe rules. A rule defines which
operations to log for a given data model.
Then, check logs in the `Reporting / Audit / Logs` menu.
-During installation, it will migrate any existing data from the `audittrail`
-module (rules and logs).
-
-For further information, please visit:
+A scheduled action exists to delete logs older than 6 months (180 days)
+automatically but is not enabled by default.
+To activate it and/or change the delay, go to the
+`Configuration / Technical / Automation / Scheduled Actions` menu and edit the
+`Auto-vacuum audit logs` entry.
- * https://www.odoo.com/forum/help-1
+During installation, a one-time script will migrate any existing data from the
+`audittrail` module (rules and logs).
Known issues / Roadmap
======================
diff --git a/auditlog/__manifest__.py b/auditlog/__manifest__.py
index 2f658faaa..e24de936c 100644
--- a/auditlog/__manifest__.py
+++ b/auditlog/__manifest__.py
@@ -21,7 +21,7 @@
{
'name': "Audit Log",
- 'version': "8.0.1.2.0",
+ 'version': "8.0.1.3.0",
'author': "ABF OSIELL,Odoo Community Association (OCA)",
'license': "AGPL-3",
'website': "http://www.osiell.com",
@@ -31,6 +31,7 @@
],
'data': [
'security/ir.model.access.csv',
+ 'data/ir_cron.xml',
'views/auditlog_view.xml',
'views/http_session_view.xml',
'views/http_request_view.xml',
diff --git a/auditlog/data/ir_cron.xml b/auditlog/data/ir_cron.xml
new file mode 100644
index 000000000..d0f77a082
--- /dev/null
+++ b/auditlog/data/ir_cron.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ Auto-vacuum audit logs
+ 1
+ days
+ -1
+
+
+ auditlog.autovacuum
+ autovacuum
+ (180,)
+
+
+
+
diff --git a/auditlog/models/__init__.py b/auditlog/models/__init__.py
index e71197ade..12345359e 100644
--- a/auditlog/models/__init__.py
+++ b/auditlog/models/__init__.py
@@ -23,3 +23,4 @@ from . import rule
from . import http_session
from . import http_request
from . import log
+from . import autovacuum
diff --git a/auditlog/models/autovacuum.py b/auditlog/models/autovacuum.py
new file mode 100644
index 000000000..078c7ef8f
--- /dev/null
+++ b/auditlog/models/autovacuum.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# © 2016 ABF OSIELL SARL, Sebastien Alix (http://osiell.com)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+import logging
+from datetime import datetime, timedelta
+
+from openerp import models, fields, api
+
+
+_logger = logging.getLogger(__name__)
+
+
+class AuditlogAutovacuum(models.TransientModel):
+ _name = 'auditlog.autovacuum'
+ _description = "Auditlog - Delete old logs"
+
+ @api.model
+ def autovacuum(self, days):
+ """Delete all logs older than ``days``. This includes:
+ - CRUD logs (create, read, write, unlink)
+ - HTTP requests
+ - HTTP user sessions
+
+ Called from a cron.
+ """
+ days = (days > 0) and int(days) or 0
+ deadline = datetime.now() - timedelta(days=days)
+ data_models = (
+ 'auditlog.log',
+ 'auditlog.http.request',
+ 'auditlog.http.session',
+ )
+ for data_model in data_models:
+ records = self.env[data_model].search(
+ [('create_date', '<=', fields.Datetime.to_string(deadline))])
+ nb_records = len(records)
+ records.unlink()
+ _logger.info(
+ u"AUTOVACUUM - %s '%s' records deleted",
+ nb_records, data_model)
+ return True
diff --git a/auditlog/models/log.py b/auditlog/models/log.py
index 908923465..2493e462e 100644
--- a/auditlog/models/log.py
+++ b/auditlog/models/log.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
#
##############################################################################
-
from openerp import models, fields
@@ -54,7 +53,7 @@ class AuditlogLogLine(models.Model):
field_id = fields.Many2one(
'ir.model.fields', ondelete='cascade', string=u"Field", required=True)
log_id = fields.Many2one(
- 'auditlog.log', string=u"Log", ondelete='cascade')
+ 'auditlog.log', string=u"Log", ondelete='cascade', index=True)
old_value = fields.Text(u"Old Value")
new_value = fields.Text(u"New Value")
old_value_text = fields.Text(u"Old value Text")
diff --git a/auditlog/tests/__init__.py b/auditlog/tests/__init__.py
index a688b88a7..94c86efac 100644
--- a/auditlog/tests/__init__.py
+++ b/auditlog/tests/__init__.py
@@ -19,3 +19,4 @@
#
##############################################################################
from . import test_auditlog
+from . import test_autovacuum
diff --git a/auditlog/tests/test_autovacuum.py b/auditlog/tests/test_autovacuum.py
new file mode 100644
index 000000000..4c017e968
--- /dev/null
+++ b/auditlog/tests/test_autovacuum.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+# © 2016 ABF OSIELL SARL, Sebastien Alix (http://osiell.com)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+import time
+
+from openerp.tests.common import TransactionCase
+
+
+class TestAuditlogAutovacuum(TransactionCase):
+
+ def setUp(self):
+ super(TestAuditlogAutovacuum, self).setUp()
+ self.groups_model_id = self.env.ref('base.model_res_groups').id
+ self.groups_rule = self.env['auditlog.rule'].create({
+ 'name': 'testrule for groups',
+ 'model_id': self.groups_model_id,
+ 'log_read': True,
+ 'log_create': True,
+ 'log_write': True,
+ 'log_unlink': True,
+ 'state': 'subscribed',
+ 'log_type': 'full',
+ })
+
+ def tearDown(self):
+ self.groups_rule.unlink()
+ super(TestAuditlogAutovacuum, self).tearDown()
+
+ def test_autovacuum(self):
+ log_model = self.env['auditlog.log']
+ autovacuum_model = self.env['auditlog.autovacuum']
+ group = self.env['res.groups'].create({
+ 'name': 'testgroup1',
+ })
+ nb_logs = log_model.search_count([
+ ('model_id', '=', self.groups_model_id),
+ ('res_id', '=', group.id),
+ ])
+ self.assertGreater(nb_logs, 0)
+ # Milliseconds are ignored by autovacuum, waiting 1s ensure that
+ # the logs generated will be processed by the vacuum
+ time.sleep(1)
+ autovacuum_model.autovacuum(days=0)
+ nb_logs = log_model.search_count([
+ ('model_id', '=', self.groups_model_id),
+ ('res_id', '=', group.id),
+ ])
+ self.assertEqual(nb_logs, 0)