Add possibility to delete attachments
parent
8265c71fa0
commit
f9e56058e2
|
@ -1,66 +0,0 @@
|
||||||
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png
|
|
||||||
:alt: License: LGPL-3
|
|
||||||
|
|
||||||
=======================
|
|
||||||
AutoVacuum Mail Message
|
|
||||||
=======================
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
Configuration
|
|
||||||
=============
|
|
||||||
|
|
||||||
* Go to the menu configuration => Technical => Email => Message vacuum Rule
|
|
||||||
* 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).
|
|
||||||
* Activate the cron AutoVacuum Mails and Messages
|
|
||||||
|
|
||||||
It is recommanded to run it frequently and when the system is not very loaded.
|
|
||||||
(For instance : once a day, during the night.)
|
|
||||||
|
|
||||||
|
|
||||||
Usage
|
|
||||||
=====
|
|
||||||
|
|
||||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
|
||||||
:alt: Try me on Runbot
|
|
||||||
:target: https://runbot.odoo-community.org/runbot/149/9.0
|
|
||||||
|
|
||||||
Bug Tracker
|
|
||||||
===========
|
|
||||||
|
|
||||||
Bugs are tracked on `GitHub Issues
|
|
||||||
<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please
|
|
||||||
check there if your issue has already been reported. If you spotted it first,
|
|
||||||
help us smash it by providing detailed and welcomed feedback.
|
|
||||||
|
|
||||||
Credits
|
|
||||||
=======
|
|
||||||
|
|
||||||
Images
|
|
||||||
------
|
|
||||||
|
|
||||||
* Odoo Community Association: `Icon <https://odoo-community.org/logo.png>`_.
|
|
||||||
|
|
||||||
Contributors
|
|
||||||
------------
|
|
||||||
|
|
||||||
* Florian da Costa <florian.dacosta@akretion.com>
|
|
||||||
|
|
||||||
Do not contact contributors directly about support or help with technical issues.
|
|
||||||
|
|
||||||
Maintainer
|
|
||||||
----------
|
|
||||||
|
|
||||||
.. image:: https://odoo-community.org/logo.png
|
|
||||||
:alt: Odoo Community Association
|
|
||||||
:target: https://odoo-community.org
|
|
||||||
|
|
||||||
This module is maintained by the OCA.
|
|
||||||
|
|
||||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
|
||||||
mission is to support the collaborative development of Odoo features and
|
|
||||||
promote its widespread use.
|
|
||||||
|
|
||||||
To contribute to this module, please visit https://odoo-community.org.
|
|
|
@ -2,20 +2,20 @@
|
||||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "AutoVacuum Mail Message",
|
"name": "AutoVacuum Mail Message and Attachment",
|
||||||
"version": "12.0.1.0.0",
|
"version": "12.0.1.0.0",
|
||||||
"category": "Tools",
|
"category": "Tools",
|
||||||
"website": "https://github.com/OCA/server-tools",
|
"website": "https://github.com/OCA/server-tools",
|
||||||
"author": "Akretion, Odoo Community Association (OCA)",
|
"author": "Akretion, Odoo Community Association (OCA)",
|
||||||
"license": "LGPL-3",
|
"license": "LGPL-3",
|
||||||
"installable": True,
|
"installable": True,
|
||||||
"summary": "Automatically delete old mail messages to clean database",
|
"summary": "Automatically delete old mail messages and attachments",
|
||||||
"depends": [
|
"depends": [
|
||||||
"mail",
|
"mail",
|
||||||
],
|
],
|
||||||
"data": [
|
"data": [
|
||||||
"data/data.xml",
|
"data/data.xml",
|
||||||
"views/message_rule_vacuum.xml",
|
"views/rule_vacuum.xml",
|
||||||
"security/ir.model.access.csv",
|
"security/ir.model.access.csv",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,22 @@
|
||||||
<field name="interval_type">days</field>
|
<field name="interval_type">days</field>
|
||||||
<field name="numbercall">-1</field>
|
<field name="numbercall">-1</field>
|
||||||
<field name="state">code</field>
|
<field name="state">code</field>
|
||||||
<field name="code">model.autovacuum_mail_message()</field>
|
<field name="code">model.autovacuum('message')</field>
|
||||||
<field eval="False" name="doall"/>
|
<field eval="False" name="doall"/>
|
||||||
<field name="model_id" ref="mail.model_mail_message"/>
|
<field name="model_id" ref="mail.model_mail_message"/>
|
||||||
</record>
|
</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>
|
</odoo>
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
|
from . import autovacuum_mixin
|
||||||
|
from . import ir_attachment
|
||||||
from . import mail_message
|
from . import mail_message
|
||||||
from . import message_vacuum_rule
|
from . import vacuum_rule
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# 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
|
||||||
|
|
||||||
|
_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:
|
||||||
|
domain = rule.get_domain()
|
||||||
|
records = self.search(domain)
|
||||||
|
records.batch_unlink()
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (C) 2018 Akretion
|
||||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||||
|
|
||||||
|
from odoo import models
|
||||||
|
|
||||||
|
|
||||||
|
class IrAttachment(models.Model):
|
||||||
|
_name = "ir.attachment"
|
||||||
|
_inherit = ["ir.attachment", "autovacuum.mixin"]
|
|
@ -1,44 +1,10 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (C) 2018 Akretion
|
# Copyright (C) 2018 Akretion
|
||||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||||
|
|
||||||
import logging
|
from odoo import models
|
||||||
|
|
||||||
import odoo
|
|
||||||
from odoo import api, models
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class MailMessage(models.Model):
|
class MailMessage(models.Model):
|
||||||
_inherit = "mail.message"
|
_name = "mail.message"
|
||||||
|
_inherit = ["mail.message", "autovacuum.mixin"]
|
||||||
@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_messages = self[0:1000]
|
|
||||||
self -= batch_delete_messages
|
|
||||||
# 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_messages.with_env(new_env).unlink()
|
|
||||||
new_env.cr.commit()
|
|
||||||
except Exception as e:
|
|
||||||
_logger.exception(
|
|
||||||
"Failed to delete messages : %s", str(e))
|
|
||||||
|
|
||||||
# Call by cron
|
|
||||||
@api.model
|
|
||||||
def autovacuum_mail_message(self):
|
|
||||||
rules = self.env['message.vacuum.rule'].search([])
|
|
||||||
for rule in rules:
|
|
||||||
domain = rule.get_message_domain()
|
|
||||||
messages = self.search(domain)
|
|
||||||
messages.batch_unlink()
|
|
||||||
|
|
|
@ -9,13 +9,13 @@ from odoo.tools.safe_eval import safe_eval
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
class MessageVacuumRule(models.Model):
|
class VacuumRule(models.Model):
|
||||||
_name = "message.vacuum.rule"
|
_name = "vacuum.rule"
|
||||||
_description = "Rules Used to delete message historic"
|
_description = "Rules Used to delete message historic"
|
||||||
|
|
||||||
@api.depends('model_ids')
|
@api.depends('model_ids')
|
||||||
@api.multi
|
@api.multi
|
||||||
def _compute_model_id(self):
|
def _get_model_id(self):
|
||||||
for rule in self:
|
for rule in self:
|
||||||
if rule.model_ids and len(rule.model_ids) == 1:
|
if rule.model_ids and len(rule.model_ids) == 1:
|
||||||
rule.model_id = rule.model_ids.id
|
rule.model_id = rule.model_ids.id
|
||||||
|
@ -23,10 +23,18 @@ class MessageVacuumRule(models.Model):
|
||||||
rule.model_id = False
|
rule.model_id = False
|
||||||
|
|
||||||
name = fields.Char(required=True)
|
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(
|
company_id = fields.Many2one(
|
||||||
'res.company', string="Company",
|
'res.company', string="Company",
|
||||||
default=lambda self: self.env['res.company']._company_default_get(
|
default=lambda self: self.env['res.company']._company_default_get(
|
||||||
'message.vacuum.rule'))
|
'vacuum.rule'))
|
||||||
message_subtype_ids = fields.Many2many(
|
message_subtype_ids = fields.Many2many(
|
||||||
'mail.message.subtype', string="Subtypes",
|
'mail.message.subtype', string="Subtypes",
|
||||||
help="Message subtypes concerned by the rule. If left empty, the "
|
help="Message subtypes concerned by the rule. If left empty, the "
|
||||||
|
@ -40,7 +48,7 @@ class MessageVacuumRule(models.Model):
|
||||||
"models into account")
|
"models into account")
|
||||||
model_id = fields.Many2one(
|
model_id = fields.Many2one(
|
||||||
'ir.model', readonly=True,
|
'ir.model', readonly=True,
|
||||||
compute='_compute_model_id',
|
compute='_get_model_id',
|
||||||
help="Technical field used to set attributes (invisible/required, "
|
help="Technical field used to set attributes (invisible/required, "
|
||||||
"domain, etc...for other fields, like the domain filter")
|
"domain, etc...for other fields, like the domain filter")
|
||||||
model_filter_domain = fields.Text(
|
model_filter_domain = fields.Text(
|
||||||
|
@ -49,7 +57,7 @@ class MessageVacuumRule(models.Model):
|
||||||
('email', 'Email'),
|
('email', 'Email'),
|
||||||
('comment', 'Comment'),
|
('comment', 'Comment'),
|
||||||
('notification', 'System notification'),
|
('notification', 'System notification'),
|
||||||
('all', 'All')], required=True)
|
('all', 'All')])
|
||||||
retention_time = fields.Integer(
|
retention_time = fields.Integer(
|
||||||
required=True, default=365,
|
required=True, default=365,
|
||||||
help="Number of days the messages concerned by this rule will be "
|
help="Number of days the messages concerned by this rule will be "
|
||||||
|
@ -67,11 +75,10 @@ class MessageVacuumRule(models.Model):
|
||||||
_("The Retention Time can't be 0 days"))
|
_("The Retention Time can't be 0 days"))
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def get_message_domain(self):
|
def _get_message_domain(self):
|
||||||
self.ensure_one()
|
|
||||||
today = date.today()
|
today = date.today()
|
||||||
limit_date = today - timedelta(days=self.retention_time)
|
limit_date = (today - timedelta(days=self.retention_time)).strftime(
|
||||||
limit_date = limit_date.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
DEFAULT_SERVER_DATE_FORMAT)
|
||||||
message_domain = [('date', '<', limit_date)]
|
message_domain = [('date', '<', limit_date)]
|
||||||
if self.message_type != 'all':
|
if self.message_type != 'all':
|
||||||
message_domain += [('message_type', '=', self.message_type)]
|
message_domain += [('message_type', '=', self.message_type)]
|
||||||
|
@ -80,24 +87,48 @@ class MessageVacuumRule(models.Model):
|
||||||
message_domain += [('model', 'in', models)]
|
message_domain += [('model', 'in', models)]
|
||||||
|
|
||||||
subtype_ids = self.message_subtype_ids.ids
|
subtype_ids = self.message_subtype_ids.ids
|
||||||
subtype_domain = []
|
|
||||||
if subtype_ids and self.empty_subtype:
|
if subtype_ids and self.empty_subtype:
|
||||||
subtype_domain = ['|', ('subtype_id', 'in', subtype_ids),
|
message_domain = ['|', ('subtype_id', 'in', subtype_ids),
|
||||||
('subtype_id', '=', False)]
|
('subtype_id', '=', False)]
|
||||||
elif subtype_ids and not self.empty_subtype:
|
elif subtype_ids and not self.empty_subtype:
|
||||||
subtype_domain += [('subtype_id', 'in', subtype_ids)]
|
message_domain += [('subtype_id', 'in', subtype_ids)]
|
||||||
elif not subtype_ids and not self.empty_subtype:
|
elif not subtype_ids and not self.empty_subtype:
|
||||||
subtype_domain += [('subtype_id', '!=', False)]
|
message_domain += [('subtype_id', '!=', False)]
|
||||||
message_domain += subtype_domain
|
return message_domain
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def _get_attachment_domain(self):
|
||||||
|
today = date.today()
|
||||||
|
limit_date = (today - timedelta(days=self.retention_time)).strftime(
|
||||||
|
DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
attachment_domain = [('create_date', '<', limit_date)]
|
||||||
|
if self.filename_pattern:
|
||||||
|
attachment_domain += [('name', 'ilike', self.filename_pattern)]
|
||||||
|
if self.model_ids:
|
||||||
|
models = self.model_ids.mapped('model')
|
||||||
|
attachment_domain += [('res_model', 'in', models)]
|
||||||
|
else:
|
||||||
|
# Avoid deleting attachment without model, if there are, it is
|
||||||
|
# probably some attachments created by Odoo
|
||||||
|
attachment_domain += [('res_model', '!=', False)]
|
||||||
|
return attachment_domain
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def get_domain(self):
|
||||||
|
self.ensure_one()
|
||||||
|
domain = []
|
||||||
|
if self.ttype == 'message':
|
||||||
|
domain += self._get_message_domain()
|
||||||
|
elif self.ttype == 'attachment':
|
||||||
|
domain += self._get_attachment_domain()
|
||||||
|
|
||||||
# Case we want a condition on linked model records
|
# Case we want a condition on linked model records
|
||||||
if self.model_id and self.model_filter_domain:
|
if self.model_id and self.model_filter_domain:
|
||||||
domain = safe_eval(self.model_filter_domain,
|
record_domain = safe_eval(self.model_filter_domain,
|
||||||
locals_dict={'datetime': datetime})
|
locals_dict={'datetime': datetime})
|
||||||
|
|
||||||
res_model = self.model_id.model
|
res_ids = self.env[self.model_id.model].with_context(
|
||||||
res_records = self.env[res_model].with_context(
|
active_test=False).search(record_domain).ids
|
||||||
active_test=False).search(domain)
|
domain += ['|', ('res_id', 'in', res_ids),
|
||||||
res_ids = res_records.ids
|
|
||||||
message_domain += ['|', ('res_id', 'in', res_ids),
|
|
||||||
('res_id', '=', False)]
|
('res_id', '=', False)]
|
||||||
return message_domain
|
return domain
|
|
@ -1,6 +1,6 @@
|
||||||
* Go to the menu configuration => Technical => Email => Message Vacuum Rules
|
* 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).
|
* 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
|
* 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.
|
It is recommanded to run it frequently and when the system is not very loaded.
|
||||||
(For instance : once a day, during the night.)
|
(For instance : once a day, during the night.)
|
||||||
|
|
|
@ -1,3 +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.
|
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 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.
|
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.
|
|
@ -1,2 +1,2 @@
|
||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
access_full_message_vaccum_rule,access.full.message.vaccum.rule,model_message_vacuum_rule,base.group_system,1,1,1,1
|
access_full_vaccum_rule,access.full.vaccum.rule,model_vacuum_rule,base.group_system,1,1,1,1
|
||||||
|
|
|
|
@ -1,4 +1,3 @@
|
||||||
# © 2018 Akretion (Florian da Costa)
|
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from . import test_message_vacuum_rule
|
from . import test_vacuum_rule
|
||||||
|
|
|
@ -5,17 +5,19 @@ from datetime import date, timedelta
|
||||||
|
|
||||||
from odoo import api, exceptions
|
from odoo import api, exceptions
|
||||||
from odoo.tests import common
|
from odoo.tests import common
|
||||||
|
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||||
|
import base64
|
||||||
|
|
||||||
|
|
||||||
class TestMessageVacuumRule(common.TransactionCase):
|
class TestVacuumRule(common.TransactionCase):
|
||||||
|
|
||||||
def create_mail_message(self, message_type, subtype):
|
def create_mail_message(self, message_type, subtype):
|
||||||
vals = {
|
vals = {
|
||||||
'message_type': message_type,
|
'message_type': message_type,
|
||||||
'subtype_id': subtype and subtype.id or False,
|
'subtype_id': subtype and subtype.id or False,
|
||||||
'date': self.before_400_days,
|
'date': self.before_400_days,
|
||||||
'model': 'mail.channel',
|
'model': 'res.partner',
|
||||||
'res_id': self.env.ref('mail.channel_all_employees').id,
|
'res_id': self.env.ref('base.partner_root').id,
|
||||||
'subject': 'Test',
|
'subject': 'Test',
|
||||||
'body': 'Body Test',
|
'body': 'Body Test',
|
||||||
}
|
}
|
||||||
|
@ -23,49 +25,51 @@ class TestMessageVacuumRule(common.TransactionCase):
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.registry.leave_test_mode()
|
self.registry.leave_test_mode()
|
||||||
super(TestMessageVacuumRule, self).tearDown()
|
super(TestVacuumRule, self).tearDown()
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestMessageVacuumRule, self).setUp()
|
super(TestVacuumRule, self).setUp()
|
||||||
self.registry.enter_test_mode(self.env.cr)
|
self.registry.enter_test_mode(self.env.cr)
|
||||||
self.env = api.Environment(self.registry.test_cr, self.env.uid,
|
self.env = api.Environment(self.registry.test_cr, self.env.uid,
|
||||||
self.env.context)
|
self.env.context)
|
||||||
self.subtype = self.env.ref('mail.mt_comment')
|
self.subtype = self.env.ref('mail.mt_comment')
|
||||||
self.message_obj = self.env['mail.message']
|
self.message_obj = self.env['mail.message']
|
||||||
self.channel_model = self.env.ref('mail.model_mail_channel')
|
self.attachment_obj = self.env['ir.attachment']
|
||||||
|
self.partner_model = self.env.ref('base.model_res_partner')
|
||||||
today = date.today()
|
today = date.today()
|
||||||
self.before_400_days = today - timedelta(days=400)
|
self.before_400_days = today - timedelta(days=400)
|
||||||
|
|
||||||
def test_mail_vacuum_rules(self):
|
def test_mail_vacuum_rules(self):
|
||||||
rule_vals = {
|
rule_vals = {
|
||||||
'name': 'Subtype Model',
|
'name': 'Subtype Model',
|
||||||
|
'ttype': 'message',
|
||||||
'retention_time': 399,
|
'retention_time': 399,
|
||||||
'message_type': 'email',
|
'message_type': 'email',
|
||||||
'model_ids': [(6, 0, [self.channel_model.id])],
|
'model_ids': [(6, 0, [self.env.ref('base.model_res_partner').id])],
|
||||||
'message_subtype_ids': [(6, 0, [self.subtype.id])],
|
'message_subtype_ids': [(6, 0, [self.subtype.id])],
|
||||||
}
|
}
|
||||||
rule = self.env['message.vacuum.rule'].create(rule_vals)
|
rule = self.env['vacuum.rule'].create(rule_vals)
|
||||||
m1 = self.create_mail_message('notification', self.subtype)
|
m1 = self.create_mail_message('notification', self.subtype)
|
||||||
m2 = self.create_mail_message('email', self.env.ref('mail.mt_note'))
|
m2 = self.create_mail_message('email', self.env.ref('mail.mt_note'))
|
||||||
m3 = self.create_mail_message('email', False)
|
m3 = self.create_mail_message('email', False)
|
||||||
message_ids = [m1.id, m2.id, m3.id]
|
message_ids = [m1.id, m2.id, m3.id]
|
||||||
self.message_obj.autovacuum_mail_message()
|
self.message_obj.autovacuum(ttype='message')
|
||||||
message = self.message_obj.search(
|
message = self.message_obj.search(
|
||||||
[('id', 'in', message_ids)])
|
[('id', 'in', message_ids)])
|
||||||
# no message deleted because either message_type is wrong or subtype
|
# no message deleted because either message_type is wrong or subtype
|
||||||
# is wront or subtype is empty
|
# is wrong or subtype is empty
|
||||||
self.assertEqual(len(message),
|
self.assertEqual(len(message),
|
||||||
3)
|
3)
|
||||||
|
|
||||||
rule.write({'message_type': 'notification', 'retention_time': 405})
|
rule.write({'message_type': 'notification', 'retention_time': 405})
|
||||||
self.message_obj.autovacuum_mail_message()
|
self.message_obj.autovacuum(ttype='message')
|
||||||
message = self.message_obj.search(
|
message = self.message_obj.search(
|
||||||
[('id', 'in', message_ids)])
|
[('id', 'in', message_ids)])
|
||||||
# no message deleted because of retention time
|
# no message deleted because of retention time
|
||||||
self.assertEqual(len(message),
|
self.assertEqual(len(message),
|
||||||
3)
|
3)
|
||||||
rule.write({'retention_time': 399})
|
rule.write({'retention_time': 399})
|
||||||
self.message_obj.autovacuum_mail_message()
|
self.message_obj.autovacuum(ttype='message')
|
||||||
message = self.message_obj.search(
|
message = self.message_obj.search(
|
||||||
[('id', 'in', message_ids)])
|
[('id', 'in', message_ids)])
|
||||||
|
|
||||||
|
@ -75,20 +79,66 @@ class TestMessageVacuumRule(common.TransactionCase):
|
||||||
rule.write({'message_type': 'email',
|
rule.write({'message_type': 'email',
|
||||||
'message_subtype_ids': [(6, 0, [])],
|
'message_subtype_ids': [(6, 0, [])],
|
||||||
'empty_subtype': True})
|
'empty_subtype': True})
|
||||||
self.message_obj.autovacuum_mail_message()
|
self.message_obj.autovacuum(ttype='message')
|
||||||
message = self.message_obj.search(
|
message = self.message_obj.search(
|
||||||
[('id', 'in', message_ids)])
|
[('id', 'in', message_ids)])
|
||||||
self.assertEqual(len(message),
|
self.assertEqual(len(message),
|
||||||
0)
|
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):
|
def test_retention_time_constraint(self):
|
||||||
rule_vals = {
|
rule_vals = {
|
||||||
'name': 'Subtype Model',
|
'name': 'Subtype Model',
|
||||||
|
'ttype': 'message',
|
||||||
'retention_time': 0,
|
'retention_time': 0,
|
||||||
'message_type': 'email',
|
'message_type': 'email',
|
||||||
}
|
}
|
||||||
with self.assertRaises(exceptions.ValidationError):
|
with self.assertRaises(exceptions.ValidationError):
|
||||||
self.env['message.vacuum.rule'].create(rule_vals)
|
self.env['vacuum.rule'].create(rule_vals)
|
||||||
|
|
||||||
def test_res_model_domain(self):
|
def test_res_model_domain(self):
|
||||||
partner = self.env['res.partner'].create({'name': 'Test Partner'})
|
partner = self.env['res.partner'].create({'name': 'Test Partner'})
|
||||||
|
@ -100,19 +150,20 @@ class TestMessageVacuumRule(common.TransactionCase):
|
||||||
|
|
||||||
rule_vals = {
|
rule_vals = {
|
||||||
'name': 'Partners',
|
'name': 'Partners',
|
||||||
|
'ttype': 'message',
|
||||||
'retention_time': 399,
|
'retention_time': 399,
|
||||||
'message_type': 'all',
|
'message_type': 'all',
|
||||||
'model_ids': [(6, 0, [partner_model.id])],
|
'model_ids': [(6, 0, [partner_model.id])],
|
||||||
'model_filter_domain': "[['name', '=', 'Dummy']]",
|
'model_filter_domain': "[['name', '=', 'Dummy']]",
|
||||||
'empty_subtype': True,
|
'empty_subtype': True,
|
||||||
}
|
}
|
||||||
rule = self.env['message.vacuum.rule'].create(rule_vals)
|
rule = self.env['vacuum.rule'].create(rule_vals)
|
||||||
self.message_obj.autovacuum_mail_message()
|
self.message_obj.autovacuum(ttype='message')
|
||||||
# no message deleted as the filter does not match
|
# no message deleted as the filter does not match
|
||||||
self.assertEqual(len(partner.message_ids), 1)
|
self.assertEqual(len(partner.message_ids), 1)
|
||||||
|
|
||||||
rule.write({
|
rule.write({
|
||||||
'model_filter_domain': "[['name', '=', 'Test Partner']]"
|
'model_filter_domain': "[['name', '=', 'Test Partner']]"
|
||||||
})
|
})
|
||||||
self.message_obj.autovacuum_mail_message()
|
self.message_obj.autovacuum(ttype='message')
|
||||||
self.assertEqual(len(partner.message_ids), 0)
|
self.assertEqual(len(partner.message_ids), 0)
|
|
@ -2,27 +2,34 @@
|
||||||
|
|
||||||
<odoo>
|
<odoo>
|
||||||
|
|
||||||
<record model="ir.ui.view" id="message_vacuum_rule_form_view">
|
<record model="ir.ui.view" id="vacuum_rule_form_view">
|
||||||
<field name="name">message.vacuum.rule.form.view</field>
|
<field name="name">vacuum.rule.form.view</field>
|
||||||
<field name="model">message.vacuum.rule</field>
|
<field name="model">vacuum.rule</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Message Vacuum Rule">
|
<form string="Message Vacuum Rule">
|
||||||
<sheet>
|
<sheet>
|
||||||
<group col="4">
|
<group col="4">
|
||||||
<group col="4" colspan="4">
|
<group col="4" colspan="4">
|
||||||
<field name="name" colspan="2"/>
|
<field name="name" colspan="2"/>
|
||||||
|
<field name="ttype" colspan="2"/>
|
||||||
<field name="company_id" colspan="2"/>
|
<field name="company_id" colspan="2"/>
|
||||||
<field name="message_type" colspan="2"/>
|
|
||||||
<field name="empty_subtype" colspan="2"/>
|
|
||||||
<field name="retention_time" colspan="2"/>
|
<field name="retention_time" colspan="2"/>
|
||||||
<field name="active" colspan="2"/>
|
<field name="active" colspan="2"/>
|
||||||
</group>
|
</group>
|
||||||
|
<group col="4" colspan="4" attrs="{'invisible': [('ttype', '!=', 'message')]}">
|
||||||
|
<field name="message_type" attrs="{'required': [('ttype', '=', 'message')]}" colspan="2"/>
|
||||||
|
<field name="empty_subtype" colspan="2"/>
|
||||||
|
<separator string="Message Subtypes" colspan="4"/>
|
||||||
|
<field name="message_subtype_ids" nolabel="1" colspan="4"/>
|
||||||
|
</group>
|
||||||
|
<group col="4" colspan="4" attrs="{'invisible': [('ttype', '!=', 'attachment')]}">
|
||||||
|
<field name="filename_pattern" colspan="2"/>
|
||||||
|
</group>
|
||||||
<separator string="Message Models" colspan="4"/>
|
<separator string="Message Models" colspan="4"/>
|
||||||
<field name="model_ids" nolabel="1" colspan="4"/>
|
<field name="model_ids" nolabel="1" colspan="4"/>
|
||||||
<field name="model_id" colspan="4"/>
|
<field name="model_id" colspan="4"/>
|
||||||
<field name="model_filter_domain" attrs="{'invisible': [('model_id', '=', False)]}" colspan="4"/>
|
<field name="model_filter_domain" attrs="{'invisible': [('model_id', '=', False)]}" colspan="4"/>
|
||||||
<separator string="Message Subtypes" colspan="4"/>
|
|
||||||
<field name="message_subtype_ids" nolabel="1" colspan="4"/>
|
|
||||||
<separator string="Description" colspan="4"/>
|
<separator string="Description" colspan="4"/>
|
||||||
<field name="description" nolabel="1" colspan="4"/>
|
<field name="description" nolabel="1" colspan="4"/>
|
||||||
</group>
|
</group>
|
||||||
|
@ -31,27 +38,25 @@
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.ui.view" id="message_vacuum_rule_tree_view">
|
<record model="ir.ui.view" id="vacuum_rule_tree_view">
|
||||||
<field name="name">message.vacuum.rule.form.view</field>
|
<field name="name">vacuum.rule.form.view</field>
|
||||||
<field name="model">message.vacuum.rule</field>
|
<field name="model">vacuum.rule</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree>
|
<tree>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="company_id"/>
|
<field name="company_id"/>
|
||||||
<field name="message_type"/>
|
|
||||||
<field name="empty_subtype"/>
|
|
||||||
<field name="retention_time"/>
|
<field name="retention_time"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.actions.act_window" id="action_message_vacuum_rule">
|
<record model="ir.actions.act_window" id="action_vacuum_rule">
|
||||||
<field name="name">Message Vacuum Rules</field>
|
<field name="name">Message and Attachment Vacuum Rule</field>
|
||||||
<field name="res_model">message.vacuum.rule</field>
|
<field name="res_model">vacuum.rule</field>
|
||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem id="menu_action_message_vacuum_rule" parent="base.menu_email" action="action_message_vacuum_rule"/>
|
<menuitem id="menu_action_vacuum_rule" parent="base.menu_email" action="action_vacuum_rule"/>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
Loading…
Reference in New Issue