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