diff --git a/mail_tracking/models/mail_tracking_email.py b/mail_tracking/models/mail_tracking_email.py index 00b35c3ca2..d858999f05 100644 --- a/mail_tracking/models/mail_tracking_email.py +++ b/mail_tracking/models/mail_tracking_email.py @@ -473,3 +473,40 @@ def event_process(self, request, post, metadata, event_type=None): # - return 'NONE' if this request is not for you # - return 'ERROR' if any error return "NONE" # pragma: no cover + + def _get_old_mail_tracking_email_domain(self, max_age_days): + target_write_date = fields.Datetime.subtract( + fields.Datetime.now(), days=max_age_days + ) + return [("write_date", "<", target_write_date)] + + @api.autovacuum + def _gc_mail_tracking_email(self, limit=5000): + config_max_age_days = ( + self.env["ir.config_parameter"] + .sudo() + .get_param("mail_tracking.mail_tracking_email_max_age_days") + ) + try: + max_age_days = int(config_max_age_days) + except ValueError: + max_age_days = 0 + + if not max_age_days > 0: + return False + + domain = self._get_old_mail_tracking_email_domain(max_age_days) + records_to_delete = self.search(domain, limit=limit).exists() + if records_to_delete: + _logger.info( + "Deleting %s mail.tracking.email records", len(records_to_delete) + ) + self.flush() + # Using a direct query to avoid ORM as it causes an issue with + # a related field mass_mailing_id in customer DB when deleting + # the records. This might be 14.0 specific, so changing to + # .unlink() should be tested when forward porting. + query = "DELETE FROM mail_tracking_email WHERE id IN %s" + args = (tuple(records_to_delete.ids),) + self.env.cr.execute(query, args) + self.invalidate_cache() diff --git a/mail_tracking/models/res_config_settings.py b/mail_tracking/models/res_config_settings.py index 5a78273b82..3136ae4ab1 100644 --- a/mail_tracking/models/res_config_settings.py +++ b/mail_tracking/models/res_config_settings.py @@ -8,3 +8,9 @@ class ResConfigSettings(models.TransientModel): related="company_id.mail_tracking_show_aliases", readonly=False, ) + mail_tracking_email_max_age_days = fields.Integer( + "Max age in days of mail tracking email records", + config_parameter="mail_tracking.mail_tracking_email_max_age_days", + help="If set as positive integer enables the deletion of " + "old mail tracking records to reduce the database size.", + ) diff --git a/mail_tracking/tests/__init__.py b/mail_tracking/tests/__init__.py index d40d444b68..76c005840b 100644 --- a/mail_tracking/tests/__init__.py +++ b/mail_tracking/tests/__init__.py @@ -2,3 +2,4 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from . import test_mail_tracking +from . import test_gc_mail_tracking_email diff --git a/mail_tracking/tests/test_gc_mail_tracking_email.py b/mail_tracking/tests/test_gc_mail_tracking_email.py new file mode 100644 index 0000000000..5754669491 --- /dev/null +++ b/mail_tracking/tests/test_gc_mail_tracking_email.py @@ -0,0 +1,87 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import fields +from odoo.tests.common import SavepointCase + + +class TestMailTrackingEmailCleanUp(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.settings = cls.env["res.config.settings"].create( + {"mail_tracking_email_max_age_days": 365} + ) + cls.settings.set_values() + cls.partner = cls.env.ref("base.res_partner_address_28") + cls.message = cls.env["mail.message"].create( + { + "model": "res.partner", + "res_id": cls.partner.id, + "body": "TEST", + "message_type": "email", + "subtype_id": cls.env.ref("mail.mt_comment").id, + "author_id": cls.partner.id, + "date": "2024-03-26", + } + ) + cls.recent_mail_tracking_email = cls.env["mail.tracking.email"].create( + {"mail_message_id": cls.message.id} + ) + # Can't set the write_date directly as it gets overwritten by the ORM + cls.old_mail_tracking_email = cls.env["mail.tracking.email"].create( + {"mail_message_id": cls.message.id} + ) + cls.total_count = 2 + cls.recent_count = 1 + cls.domain = [ + ("mail_message_id", "=", cls.message.id), + ] + + def _set_write_date(self): + # Set the write_date of the old record to be older than the max_age_days + # Update DB directly to avoid ORM overwriting the write_date + old_write_date = fields.Datetime.subtract(fields.Datetime.now(), days=400) + self.env.cr.execute( + "UPDATE mail_tracking_email SET write_date = %s WHERE id = %s", + (old_write_date, self.old_mail_tracking_email.id), + ) + + def test_deletion_of_mail_tracking_email(self): + self._set_write_date() + self.assertEqual( + len(self.env["mail.tracking.email"].search(self.domain)), self.total_count + ) + self.env["mail.tracking.email"]._gc_mail_tracking_email() + self.assertEqual( + len(self.env["mail.tracking.email"].search(self.domain)), self.recent_count + ) + self.assertTrue(self.recent_mail_tracking_email.exists()) + + def test_deletion_follows_configuration_variable(self): + self._set_write_date() + self.assertEqual( + len(self.env["mail.tracking.email"].search(self.domain)), self.total_count + ) + # when disabled, no deletions should happen + self.settings.mail_tracking_email_max_age_days = 0 + self.settings.set_values() + self.env["mail.tracking.email"]._gc_mail_tracking_email() + self.assertEqual( + len(self.env["mail.tracking.email"].search(self.domain)), self.total_count + ) + # when disabled, no deletions should happen + self.settings.mail_tracking_email_max_age_days = -1 + self.settings.set_values() + self.env["mail.tracking.email"]._gc_mail_tracking_email() + self.assertEqual( + len(self.env["mail.tracking.email"].search(self.domain)), self.total_count + ) + # when enabled, deletions should happen + self.settings.mail_tracking_email_max_age_days = 365 + self.settings.set_values() + self.env["mail.tracking.email"]._gc_mail_tracking_email() + self.assertEqual( + len(self.env["mail.tracking.email"].search(self.domain)), self.recent_count + ) diff --git a/mail_tracking/views/res_config_settings.xml b/mail_tracking/views/res_config_settings.xml index d7edcafbac..be5f2fa599 100644 --- a/mail_tracking/views/res_config_settings.xml +++ b/mail_tracking/views/res_config_settings.xml @@ -19,6 +19,28 @@ +
+
+ +
+
+
+
+
+