OCA-git-bot
5 years ago
20 changed files with 880 additions and 0 deletions
-
1autovacuum_message_attachment/__init__.py
-
21autovacuum_message_attachment/__manifest__.py
-
31autovacuum_message_attachment/data/data.xml
-
158autovacuum_message_attachment/i18n/autovacuum_mail_message.pot
-
180autovacuum_message_attachment/i18n/fr.po
-
5autovacuum_message_attachment/models/__init__.py
-
71autovacuum_message_attachment/models/autovacuum_mixin.py
-
13autovacuum_message_attachment/models/base.py
-
27autovacuum_message_attachment/models/ir_attachment.py
-
32autovacuum_message_attachment/models/mail_message.py
-
86autovacuum_message_attachment/models/vacuum_rule.py
-
6autovacuum_message_attachment/readme/CONFIGURE.rst
-
2autovacuum_message_attachment/readme/CONTRIBUTORS.rst
-
4autovacuum_message_attachment/readme/DESCRIPTION.rst
-
2autovacuum_message_attachment/readme/ROADMAP.rst
-
2autovacuum_message_attachment/security/ir.model.access.csv
-
BINautovacuum_message_attachment/static/description/icon.png
-
3autovacuum_message_attachment/tests/__init__.py
-
169autovacuum_message_attachment/tests/test_vacuum_rule.py
-
67autovacuum_message_attachment/views/rule_vacuum.xml
@ -0,0 +1 @@ |
|||
from . import models |
@ -0,0 +1,21 @@ |
|||
# Copyright (C) 2018 Akretion |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
{ |
|||
"name": "AutoVacuum Mail Message and Attachment", |
|||
"version": "12.0.1.0.0", |
|||
"category": "Tools", |
|||
"website": "https://github.com/OCA/server-tools", |
|||
"author": "Akretion, Odoo Community Association (OCA)", |
|||
"license": "LGPL-3", |
|||
"installable": True, |
|||
"summary": "Automatically delete old mail messages and attachments", |
|||
"depends": [ |
|||
"mail", |
|||
], |
|||
"data": [ |
|||
"data/data.xml", |
|||
"views/rule_vacuum.xml", |
|||
"security/ir.model.access.csv", |
|||
], |
|||
} |
@ -0,0 +1,31 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
|
|||
<odoo noupdate="1"> |
|||
|
|||
<record id="ir_cron_vacuum_message" model="ir.cron"> |
|||
<field name="name">AutoVacuum Mails and Messages</field> |
|||
<field eval="False" name="active"/> |
|||
<field name="user_id" ref="base.user_root"/> |
|||
<field name="interval_number">1</field> |
|||
<field name="interval_type">days</field> |
|||
<field name="numbercall">-1</field> |
|||
<field name="state">code</field> |
|||
<field name="code">model.autovacuum('message')</field> |
|||
<field eval="False" name="doall"/> |
|||
<field name="model_id" ref="mail.model_mail_message"/> |
|||
</record> |
|||
|
|||
<record id="ir_cron_vacuum_attachment" model="ir.cron"> |
|||
<field name="name">AutoVacuum Attachments</field> |
|||
<field eval="False" name="active"/> |
|||
<field name="user_id" ref="base.user_root"/> |
|||
<field name="interval_number">1</field> |
|||
<field name="interval_type">days</field> |
|||
<field name="numbercall">-1</field> |
|||
<field name="state">code</field> |
|||
<field name="code">model.autovacuum('attachment')</field> |
|||
<field eval="False" name="doall"/> |
|||
<field name="model_id" ref="base.model_ir_attachment"/> |
|||
</record> |
|||
|
|||
</odoo> |
@ -0,0 +1,158 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * autovacuum_mail_message |
|||
# |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: Odoo Server 9.0c\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"Last-Translator: <>\n" |
|||
"Language-Team: \n" |
|||
"MIME-Version: 1.0\n" |
|||
"Content-Type: text/plain; charset=UTF-8\n" |
|||
"Content-Transfer-Encoding: \n" |
|||
"Plural-Forms: \n" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: selection:message.vacuum.rule,message_type:0 |
|||
msgid "All" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: selection:message.vacuum.rule,message_type:0 |
|||
msgid "Comment" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_company_id |
|||
msgid "Company" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_create_uid |
|||
msgid "Created by" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_create_date |
|||
msgid "Created on" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_display_name |
|||
msgid "Display Name" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: selection:message.vacuum.rule,message_type:0 |
|||
msgid "Email" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_empty_subtype |
|||
msgid "Empty subtype" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_id |
|||
msgid "ID" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule___last_update |
|||
msgid "Last Modified on" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_write_uid |
|||
msgid "Last Updated by" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_write_date |
|||
msgid "Last Updated on" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model,name:autovacuum_mail_message.model_mail_message |
|||
msgid "Message" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.ui.view,arch_db:autovacuum_mail_message.message_vacuum_rule_form_view |
|||
msgid "Message Models" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.ui.view,arch_db:autovacuum_mail_message.message_vacuum_rule_form_view |
|||
msgid "Message Subtypes" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.actions.act_window,name:autovacuum_mail_message.action_message_vacuum_rule |
|||
#: model:ir.ui.menu,name:autovacuum_mail_message.menu_action_message_vacuum_rule |
|||
#: model:ir.ui.view,arch_db:autovacuum_mail_message.message_vacuum_rule_form_view |
|||
msgid "Message Vacuum Rule" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,help:autovacuum_mail_message.field_message_vacuum_rule_message_subtype_ids |
|||
msgid "Message subtypes concerned by the rule. If left empty, the system won't take the subtype into account to find the messages to delete" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_message_type |
|||
msgid "Message type" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_model_ids |
|||
msgid "Models" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,help:autovacuum_mail_message.field_message_vacuum_rule_model_ids |
|||
msgid "Models concerned by the rule. If left empty, it will take all models into account" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_name |
|||
msgid "Name" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,help:autovacuum_mail_message.field_message_vacuum_rule_retention_time |
|||
msgid "Number of days the messages concerned by this rule will be keeped in the database after creation. Once the delay is passed, they will be automatically deleted." |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_retention_time |
|||
msgid "Retention time" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model,name:autovacuum_mail_message.model_message_vacuum_rule |
|||
msgid "Rules Used to delete message historic" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_message_subtype_ids |
|||
msgid "Subtypes" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: selection:message.vacuum.rule,message_type:0 |
|||
msgid "System notification" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,help:autovacuum_mail_message.field_message_vacuum_rule_empty_subtype |
|||
msgid "Take also into account messages with no subtypes" |
|||
msgstr "" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: code:addons/autovacuum_mail_message/models/message_vacuum_rule.py:48 |
|||
#, python-format |
|||
msgid "The Retention Time can't be 0 days" |
|||
msgstr "" |
|||
|
@ -0,0 +1,180 @@ |
|||
# Translation of Odoo Server. |
|||
# This file contains the translation of the following modules: |
|||
# * autovacuum_mail_message |
|||
# |
|||
msgid "" |
|||
msgstr "" |
|||
"Project-Id-Version: Odoo Server 9.0c\n" |
|||
"Report-Msgid-Bugs-To: \n" |
|||
"POT-Creation-Date: 2018-03-29 11:30+0000\n" |
|||
"PO-Revision-Date: 2018-03-29 11:30+0000\n" |
|||
"Last-Translator: <>\n" |
|||
"Language-Team: \n" |
|||
"Language: \n" |
|||
"MIME-Version: 1.0\n" |
|||
"Content-Type: text/plain; charset=UTF-8\n" |
|||
"Content-Transfer-Encoding: \n" |
|||
"Plural-Forms: \n" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: selection:message.vacuum.rule,message_type:0 |
|||
msgid "All" |
|||
msgstr "Tous" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: selection:message.vacuum.rule,message_type:0 |
|||
msgid "Comment" |
|||
msgstr "Commentaires" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_company_id |
|||
msgid "Company" |
|||
msgstr "Société" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_create_uid |
|||
msgid "Created by" |
|||
msgstr "Créé par" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_create_date |
|||
msgid "Created on" |
|||
msgstr "Créé le" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_display_name |
|||
msgid "Display Name" |
|||
msgstr "Nom à afficher" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: selection:message.vacuum.rule,message_type:0 |
|||
msgid "Email" |
|||
msgstr "Email" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_empty_subtype |
|||
msgid "Empty subtype" |
|||
msgstr "Sous-type Vide" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_id |
|||
msgid "ID" |
|||
msgstr "ID" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule___last_update |
|||
msgid "Last Modified on" |
|||
msgstr "Dernière modification le" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_write_uid |
|||
msgid "Last Updated by" |
|||
msgstr "Dernière modification par" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_write_date |
|||
msgid "Last Updated on" |
|||
msgstr "Dernière mise à jour le" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model,name:autovacuum_mail_message.model_mail_message |
|||
msgid "Message" |
|||
msgstr "Message" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.ui.view,arch_db:autovacuum_mail_message.message_vacuum_rule_form_view |
|||
msgid "Message Models" |
|||
msgstr "Documents des messages" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.ui.view,arch_db:autovacuum_mail_message.message_vacuum_rule_form_view |
|||
msgid "Message Subtypes" |
|||
msgstr "Sous-types des messages" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.actions.act_window,name:autovacuum_mail_message.action_message_vacuum_rule |
|||
#: model:ir.ui.menu,name:autovacuum_mail_message.menu_action_message_vacuum_rule |
|||
#: model:ir.ui.view,arch_db:autovacuum_mail_message.message_vacuum_rule_form_view |
|||
msgid "Message Vacuum Rule" |
|||
msgstr "Règle de supression des messages" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,help:autovacuum_mail_message.field_message_vacuum_rule_message_subtype_ids |
|||
msgid "" |
|||
"Message subtypes concerned by the rule. If left empty, the system won't take " |
|||
"the subtype into account to find the messages to delete" |
|||
msgstr "" |
|||
"Sous-types de message concernés par cette règle. Si c'est laissé vide, le " |
|||
"système ne prendra pas en compte les sous type pour trouver les messages à " |
|||
"supprimer" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_message_type |
|||
msgid "Message type" |
|||
msgstr "Type de message" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_model_ids |
|||
msgid "Models" |
|||
msgstr "Documents" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,help:autovacuum_mail_message.field_message_vacuum_rule_model_ids |
|||
msgid "" |
|||
"Models concerned by the rule. If left empty, it will take all models into " |
|||
"account" |
|||
msgstr "" |
|||
"Documents concernés par la règle. Si c'est laissé vide, les messages de tous " |
|||
"les modèles seront pris en compte" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_name |
|||
msgid "Name" |
|||
msgstr "Nom" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,help:autovacuum_mail_message.field_message_vacuum_rule_retention_time |
|||
msgid "" |
|||
"Number of days the messages concerned by this rule will be keeped in the " |
|||
"database after creation. Once the delay is passed, they will be " |
|||
"automatically deleted." |
|||
msgstr "" |
|||
"Nombre de jour de rétention des messages concerné par la règle. Une fois ce " |
|||
"délai passé, les messages sont automatiquement supprimés" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_retention_time |
|||
msgid "Retention time" |
|||
msgstr "Temps de rétention" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model,name:autovacuum_mail_message.model_message_vacuum_rule |
|||
msgid "Rules Used to delete message historic" |
|||
msgstr "Règle de supression automatique de message" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,field_description:autovacuum_mail_message.field_message_vacuum_rule_message_subtype_ids |
|||
msgid "Subtypes" |
|||
msgstr "Sous-types" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: selection:message.vacuum.rule,message_type:0 |
|||
msgid "System notification" |
|||
msgstr "Notification Système" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: model:ir.model.fields,help:autovacuum_mail_message.field_message_vacuum_rule_empty_subtype |
|||
msgid "Take also into account messages with no subtypes" |
|||
msgstr "Prend également en compte les messages sans aucun sous-type" |
|||
|
|||
#. module: autovacuum_mail_message |
|||
#: code:addons/autovacuum_mail_message/models/message_vacuum_rule.py:48 |
|||
#, python-format |
|||
msgid "The Retention Time can't be 0 days" |
|||
msgstr "Le temps de retention ne peut pas être de 0 jours." |
|||
|
|||
#~ msgid "Companies" |
|||
#~ msgstr "Sociétés" |
|||
|
|||
#~ msgid "mail_message_subtype" |
|||
#~ msgstr "mail_message_subtype" |
@ -0,0 +1,5 @@ |
|||
from . import autovacuum_mixin |
|||
from . import ir_attachment |
|||
from . import mail_message |
|||
from . import vacuum_rule |
|||
from . import base |
@ -0,0 +1,71 @@ |
|||
# Copyright (C) 2019 Akretion |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
import logging |
|||
|
|||
import odoo |
|||
from odoo import api, models |
|||
from odoo.tools.safe_eval import safe_eval |
|||
import datetime |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class AutovacuumMixin(models.AbstractModel): |
|||
_name = "autovacuum.mixin" |
|||
_description = "Mixin used to delete messages or attachments" |
|||
|
|||
@api.multi |
|||
def batch_unlink(self): |
|||
with api.Environment.manage(): |
|||
with odoo.registry( |
|||
self.env.cr.dbname).cursor() as new_cr: |
|||
new_env = api.Environment(new_cr, self.env.uid, |
|||
self.env.context) |
|||
try: |
|||
while self: |
|||
batch_delete = self[0:1000] |
|||
self -= batch_delete |
|||
# do not attach new env to self because it may be |
|||
# huge, and the cache is cleaned after each unlink |
|||
# so we do not want to much record is the env in |
|||
# which we call unlink because odoo would prefetch |
|||
# fields, cleared right after. |
|||
batch_delete.with_env(new_env).unlink() |
|||
new_env.cr.commit() |
|||
except Exception as e: |
|||
_logger.exception( |
|||
"Failed to delete Ms : %s" % (self._name, str(e))) |
|||
|
|||
# Call by cron |
|||
@api.model |
|||
def autovacuum(self, ttype='message'): |
|||
rules = self.env['vacuum.rule'].search([('ttype', '=', ttype)]) |
|||
for rule in rules: |
|||
records = rule._search_autovacuum_records() |
|||
records.batch_unlink() |
|||
|
|||
def _get_autovacuum_domain(self, rule): |
|||
return [] |
|||
|
|||
def _get_autovacuum_records(self, rule): |
|||
if rule.model_id and rule.model_filter_domain: |
|||
return self._get_autovacuum_records_model(rule) |
|||
return self.search(self._get_autovacuum_domain(rule)) |
|||
|
|||
def _get_autovacuum_records_model(self, rule): |
|||
domain = self._get_autovacuum_domain(rule) |
|||
record_domain = safe_eval(rule.model_filter_domain, |
|||
locals_dict={'datetime': datetime}) |
|||
autovacuum_relation = self._autovacuum_relation |
|||
for leaf in domain: |
|||
if not isinstance(leaf, (tuple, list)): |
|||
record_domain.append(leaf) |
|||
continue |
|||
field, operator, value = leaf |
|||
record_domain.append( |
|||
('%s.%s' % (autovacuum_relation, field), operator, value)) |
|||
records = self.env[rule.model_id.model].search(record_domain) |
|||
return self.search( |
|||
domain + [('res_id', 'in', records.ids)] |
|||
) |
@ -0,0 +1,13 @@ |
|||
# Copyright (C) 2019 Akretion |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from odoo import fields, models |
|||
|
|||
|
|||
class Base(models.AbstractModel): |
|||
_inherit = "base" |
|||
|
|||
attachment_ids = fields.One2many( |
|||
'ir.attachment', 'res_id', string='Attachments', |
|||
domain=lambda self: [('res_model', '=', self._name)], auto_join=True |
|||
) |
@ -0,0 +1,27 @@ |
|||
# Copyright (C) 2018 Akretion |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from odoo import fields, models |
|||
from datetime import timedelta |
|||
|
|||
|
|||
class IrAttachment(models.Model): |
|||
_name = "ir.attachment" |
|||
_inherit = ["ir.attachment", "autovacuum.mixin"] |
|||
_autovacuum_relation = 'attachment_ids' |
|||
|
|||
def _get_autovacuum_domain(self, rule): |
|||
domain = super()._get_autovacuum_domain(rule) |
|||
today = fields.Datetime.now() |
|||
limit_date = today - timedelta(days=rule.retention_time) |
|||
domain += [('create_date', '<', limit_date)] |
|||
if rule.filename_pattern: |
|||
domain += [('name', 'ilike', rule.filename_pattern)] |
|||
if rule.model_ids: |
|||
models = rule.model_ids.mapped('model') |
|||
domain += [('res_model', 'in', models)] |
|||
else: |
|||
# Avoid deleting attachment without model, if there are, it is |
|||
# probably some attachments created by Odoo |
|||
domain += [('res_model', '!=', False)] |
|||
return domain |
@ -0,0 +1,32 @@ |
|||
# Copyright (C) 2018 Akretion |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from odoo import fields, models |
|||
from datetime import timedelta |
|||
|
|||
|
|||
class MailMessage(models.Model): |
|||
_name = "mail.message" |
|||
_inherit = ["mail.message", "autovacuum.mixin"] |
|||
_autovacuum_relation = 'message_ids' |
|||
|
|||
def _get_autovacuum_domain(self, rule): |
|||
domain = super()._get_autovacuum_domain(rule) |
|||
today = fields.Datetime.now() |
|||
limit_date = today - timedelta(days=rule.retention_time) |
|||
domain += [('date', '<', limit_date)] |
|||
if rule.message_type != 'all': |
|||
domain += [('message_type', '=', rule.message_type)] |
|||
if rule.model_ids: |
|||
models = rule.model_ids.mapped('model') |
|||
domain += [('model', 'in', models)] |
|||
subtype_ids = rule.message_subtype_ids.ids |
|||
if subtype_ids and rule.empty_subtype: |
|||
domain = [ |
|||
'|', ('subtype_id', 'in', subtype_ids), |
|||
('subtype_id', '=', False)] |
|||
elif subtype_ids and not rule.empty_subtype: |
|||
domain += [('subtype_id', 'in', subtype_ids)] |
|||
elif not subtype_ids and not rule.empty_subtype: |
|||
domain += [('subtype_id', '!=', False)] |
|||
return domain |
@ -0,0 +1,86 @@ |
|||
# Copyright (C) 2018 Akretion |
|||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
|||
|
|||
from odoo import _, api, exceptions, fields, models |
|||
|
|||
|
|||
class VacuumRule(models.Model): |
|||
_name = "vacuum.rule" |
|||
_description = "Rules Used to delete message historic" |
|||
|
|||
@api.depends('model_ids') |
|||
@api.multi |
|||
def _get_model_id(self): |
|||
for rule in self: |
|||
if rule.model_ids and len(rule.model_ids) == 1: |
|||
rule.model_id = rule.model_ids.id |
|||
rule.model = rule.model_id.model |
|||
else: |
|||
rule.model_id = False |
|||
rule.model = False |
|||
|
|||
name = fields.Char(required=True) |
|||
ttype = fields.Selection( |
|||
selection=[('attachment', 'Attachment'), |
|||
('message', 'Message')], |
|||
string="Type", |
|||
required=True) |
|||
filename_pattern = fields.Char( |
|||
help=("If set, only attachments containing this pattern will be" |
|||
" deleted.")) |
|||
company_id = fields.Many2one( |
|||
'res.company', string="Company", |
|||
default=lambda self: self.env['res.company']._company_default_get( |
|||
'vacuum.rule')) |
|||
message_subtype_ids = fields.Many2many( |
|||
'mail.message.subtype', string="Subtypes", |
|||
help="Message subtypes concerned by the rule. If left empty, the " |
|||
"system won't take the subtype into account to find the " |
|||
"messages to delete") |
|||
empty_subtype = fields.Boolean( |
|||
help="Take also into account messages with no subtypes") |
|||
model_ids = fields.Many2many( |
|||
'ir.model', string="Models", |
|||
help="Models concerned by the rule. If left empty, it will take all " |
|||
"models into account") |
|||
model_id = fields.Many2one( |
|||
'ir.model', readonly=True, |
|||
compute='_get_model_id', |
|||
help="Technical field used to set attributes (invisible/required, " |
|||
"domain, etc...for other fields, like the domain filter") |
|||
model_filter_domain = fields.Text( |
|||
string='Model Filter Domain') |
|||
model = fields.Char( |
|||
readonly=True, |
|||
compute='_get_model_id', |
|||
string='Model code' |
|||
) |
|||
message_type = fields.Selection([ |
|||
('email', 'Email'), |
|||
('comment', 'Comment'), |
|||
('notification', 'System notification'), |
|||
('all', 'All')]) |
|||
retention_time = fields.Integer( |
|||
required=True, default=365, |
|||
help="Number of days the messages concerned by this rule will be " |
|||
"keeped in the database after creation. Once the delay is " |
|||
"passed, they will be automatically deleted.") |
|||
active = fields.Boolean(default=True) |
|||
description = fields.Text() |
|||
|
|||
@api.multi |
|||
@api.constrains('retention_time') |
|||
def retention_time_not_null(self): |
|||
for rule in self: |
|||
if not rule.retention_time: |
|||
raise exceptions.ValidationError( |
|||
_("The Retention Time can't be 0 days")) |
|||
|
|||
def _search_autovacuum_records(self): |
|||
self.ensure_one() |
|||
model = self.ttype |
|||
if model == 'message': |
|||
model = 'mail.message' |
|||
elif model == 'attachment': |
|||
model = 'ir.attachment' |
|||
return self.env[model]._get_autovacuum_records(self) |
@ -0,0 +1,6 @@ |
|||
* Go to the menu configuration => Technical => Email => Message And Attachment Vacuum Rules |
|||
* Add the adequates rules for your company. On each rule, you can indicate the models, type and subtypes for which you want to delete the messages, along with a retention time (in days). Or for attachment, you can specify a substring of the name. |
|||
* Activate the cron AutoVacuum Mails and Messages and/or AutoVacuum Attachments |
|||
|
|||
It is recommanded to run it frequently and when the system is not very loaded. |
|||
(For instance : once a day, during the night.) |
@ -0,0 +1,2 @@ |
|||
* Florian da Costa <florian.dacosta@akretion.com> |
|||
* Enric Tobella <etobella@creublanca.es> |
@ -0,0 +1,4 @@ |
|||
Odoo create a lot of message and/or mails. With time it can slow the system or take a lot of disk space. |
|||
The goal of this module is to clean these message once they are obsolete. |
|||
The same may happen with attachment that we store. |
|||
You can choose various criterias manage which messages you want to delete automatically. |
@ -0,0 +1,2 @@ |
|||
You have to be careful with rules regarding attachment deletion because Odoo find the attachment to delete with their name. |
|||
Odoo will find all attachments containing the substring configured on the rule, so you have to be specific enough on the other criterias (concerned models...) to avoid unwanted attachment deletion. |
@ -0,0 +1,2 @@ |
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
|||
access_full_vaccum_rule,access.full.vaccum.rule,model_vacuum_rule,base.group_system,1,1,1,1 |
After Width: 128 | Height: 128 | Size: 9.2 KiB |
@ -0,0 +1,3 @@ |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from . import test_vacuum_rule |
@ -0,0 +1,169 @@ |
|||
# © 2018 Akretion (Florian da Costa) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from datetime import date, timedelta |
|||
|
|||
from odoo import api, exceptions |
|||
from odoo.tests import common |
|||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT |
|||
import base64 |
|||
|
|||
|
|||
class TestVacuumRule(common.TransactionCase): |
|||
|
|||
def create_mail_message(self, message_type, subtype): |
|||
vals = { |
|||
'message_type': message_type, |
|||
'subtype_id': subtype and subtype.id or False, |
|||
'date': self.before_400_days, |
|||
'model': 'res.partner', |
|||
'res_id': self.env.ref('base.partner_root').id, |
|||
'subject': 'Test', |
|||
'body': 'Body Test', |
|||
} |
|||
return self.message_obj.create(vals) |
|||
|
|||
def tearDown(self): |
|||
self.registry.leave_test_mode() |
|||
super(TestVacuumRule, self).tearDown() |
|||
|
|||
def setUp(self): |
|||
super(TestVacuumRule, self).setUp() |
|||
self.registry.enter_test_mode(self.env.cr) |
|||
self.env = api.Environment(self.registry.test_cr, self.env.uid, |
|||
self.env.context) |
|||
self.subtype = self.env.ref('mail.mt_comment') |
|||
self.message_obj = self.env['mail.message'] |
|||
self.attachment_obj = self.env['ir.attachment'] |
|||
self.partner_model = self.env.ref('base.model_res_partner') |
|||
today = date.today() |
|||
self.before_400_days = today - timedelta(days=400) |
|||
|
|||
def test_mail_vacuum_rules(self): |
|||
rule_vals = { |
|||
'name': 'Subtype Model', |
|||
'ttype': 'message', |
|||
'retention_time': 399, |
|||
'message_type': 'email', |
|||
'model_ids': [(6, 0, [self.env.ref('base.model_res_partner').id])], |
|||
'message_subtype_ids': [(6, 0, [self.subtype.id])], |
|||
} |
|||
rule = self.env['vacuum.rule'].create(rule_vals) |
|||
m1 = self.create_mail_message('notification', self.subtype) |
|||
m2 = self.create_mail_message('email', self.env.ref('mail.mt_note')) |
|||
m3 = self.create_mail_message('email', False) |
|||
message_ids = [m1.id, m2.id, m3.id] |
|||
self.message_obj.autovacuum(ttype='message') |
|||
message = self.message_obj.search( |
|||
[('id', 'in', message_ids)]) |
|||
# no message deleted because either message_type is wrong or subtype |
|||
# is wrong or subtype is empty |
|||
self.assertEqual(len(message), |
|||
3) |
|||
|
|||
rule.write({'message_type': 'notification', 'retention_time': 405}) |
|||
self.message_obj.autovacuum(ttype='message') |
|||
message = self.message_obj.search( |
|||
[('id', 'in', message_ids)]) |
|||
# no message deleted because of retention time |
|||
self.assertEqual(len(message), |
|||
3) |
|||
rule.write({'retention_time': 399}) |
|||
self.message_obj.autovacuum(ttype='message') |
|||
message = self.message_obj.search( |
|||
[('id', 'in', message_ids)]) |
|||
|
|||
self.assertEqual(len(message), |
|||
2) |
|||
|
|||
rule.write({'message_type': 'email', |
|||
'message_subtype_ids': [(6, 0, [])], |
|||
'empty_subtype': True}) |
|||
self.message_obj.autovacuum(ttype='message') |
|||
message = self.message_obj.search( |
|||
[('id', 'in', message_ids)]) |
|||
self.assertEqual(len(message), |
|||
0) |
|||
|
|||
def create_attachment(self, name): |
|||
vals = { |
|||
'name': name, |
|||
'datas': base64.b64encode(b'Content'), |
|||
'datas_fname': name, |
|||
'res_id': self.env.ref('base.partner_root').id, |
|||
'res_model': 'res.partner', |
|||
} |
|||
return self.env['ir.attachment'].create(vals) |
|||
|
|||
def test_attachment_vacuum_rule(self): |
|||
rule_vals = { |
|||
'name': 'Partner Attachments', |
|||
'ttype': 'attachment', |
|||
'retention_time': 100, |
|||
'model_ids': [(6, 0, [self.partner_model.id])], |
|||
'filename_pattern': 'test', |
|||
} |
|||
self.env['vacuum.rule'].create(rule_vals) |
|||
a1 = self.create_attachment('Test-dummy') |
|||
a2 = self.create_attachment('test24') |
|||
# Force create date to old date to test deletion with 100 days |
|||
# retention time |
|||
before_102_days = date.today() - timedelta(days=102) |
|||
before_102_days_str = before_102_days.strftime( |
|||
DEFAULT_SERVER_DATE_FORMAT) |
|||
self.env.cr.execute(""" |
|||
UPDATE ir_attachment SET create_date = '%s' |
|||
WHERE id = %s |
|||
""" % (before_102_days_str, a2.id)) |
|||
a2.write({'create_date': date.today() - timedelta(days=102)}) |
|||
a3 = self.create_attachment('other') |
|||
self.env.cr.execute(""" |
|||
UPDATE ir_attachment SET create_date = '%s' |
|||
WHERE id = %s |
|||
""" % (before_102_days_str, a3.id)) |
|||
attachment_ids = [a1.id, a2.id, a3.id] |
|||
self.attachment_obj.autovacuum(ttype='attachment') |
|||
attachments = self.attachment_obj.search( |
|||
[('id', 'in', attachment_ids)]) |
|||
# Only one message deleted because other 2 are with bad name or to |
|||
# recent. |
|||
self.assertEqual(len(attachments), |
|||
2) |
|||
|
|||
def test_retention_time_constraint(self): |
|||
rule_vals = { |
|||
'name': 'Subtype Model', |
|||
'ttype': 'message', |
|||
'retention_time': 0, |
|||
'message_type': 'email', |
|||
} |
|||
with self.assertRaises(exceptions.ValidationError): |
|||
self.env['vacuum.rule'].create(rule_vals) |
|||
|
|||
def test_res_model_domain(self): |
|||
partner = self.env['res.partner'].create({'name': 'Test Partner'}) |
|||
# automatic creation message |
|||
self.assertEqual(len(partner.message_ids), 1) |
|||
# change date message to simulate it is an old one |
|||
partner.message_ids.write({'date': '2017-01-01'}) |
|||
partner_model = self.env.ref('base.model_res_partner') |
|||
|
|||
rule_vals = { |
|||
'name': 'Partners', |
|||
'ttype': 'message', |
|||
'retention_time': 399, |
|||
'message_type': 'all', |
|||
'model_ids': [(6, 0, [partner_model.id])], |
|||
'model_filter_domain': "[['name', '=', 'Dummy']]", |
|||
'empty_subtype': True, |
|||
} |
|||
rule = self.env['vacuum.rule'].create(rule_vals) |
|||
self.message_obj.autovacuum(ttype='message') |
|||
# no message deleted as the filter does not match |
|||
self.assertEqual(len(partner.message_ids), 1) |
|||
|
|||
rule.write({ |
|||
'model_filter_domain': "[['name', '=', 'Test Partner']]" |
|||
}) |
|||
self.message_obj.autovacuum(ttype='message') |
|||
self.assertEqual(len(partner.message_ids), 0) |
@ -0,0 +1,67 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
|
|||
<odoo> |
|||
|
|||
<record model="ir.ui.view" id="vacuum_rule_form_view"> |
|||
<field name="name">vacuum.rule.form.view</field> |
|||
<field name="model">vacuum.rule</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="Message Vacuum Rule"> |
|||
<sheet> |
|||
<group col="1"> |
|||
<group col="4"> |
|||
<field name="name"/> |
|||
<field name="ttype"/> |
|||
<field name="company_id"/> |
|||
<field name="retention_time"/> |
|||
<field name="active"/> |
|||
</group> |
|||
<group col="4" attrs="{'invisible': [('ttype', '!=', 'message')]}"> |
|||
<field name="message_type" attrs="{'required': [('ttype', '=', 'message')]}"/> |
|||
<field name="empty_subtype"/> |
|||
</group> |
|||
<group string="Message Subtypes"> |
|||
<field name="message_subtype_ids" nolabel="1"/> |
|||
</group> |
|||
<group attrs="{'invisible': [('ttype', '!=', 'attachment')]}"> |
|||
<field name="filename_pattern"/> |
|||
</group> |
|||
<group string="Message Models"> |
|||
<field name="model_ids" nolabel="1"/> |
|||
</group> |
|||
<group> |
|||
<field name="model_id"/> |
|||
<field name="model" invisible="1"/> |
|||
<field name="model_filter_domain" attrs="{'invisible': [('model_id', '=', False)]}" widget="domain" options="{'model': 'model'}"/> |
|||
</group> |
|||
<group string="Description"> |
|||
<field name="description"/> |
|||
</group> |
|||
</group> |
|||
</sheet> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<record model="ir.ui.view" id="vacuum_rule_tree_view"> |
|||
<field name="name">vacuum.rule.form.view</field> |
|||
<field name="model">vacuum.rule</field> |
|||
<field name="arch" type="xml"> |
|||
<tree> |
|||
<field name="name"/> |
|||
<field name="company_id"/> |
|||
<field name="retention_time"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
|
|||
<record model="ir.actions.act_window" id="action_vacuum_rule"> |
|||
<field name="name">Message and Attachment Vacuum Rule</field> |
|||
<field name="res_model">vacuum.rule</field> |
|||
<field name="view_type">form</field> |
|||
<field name="view_mode">tree,form</field> |
|||
</record> |
|||
|
|||
<menuitem id="menu_action_vacuum_rule" parent="base.menu_email" action="action_vacuum_rule"/> |
|||
|
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue