From 044014505138674b39c4a082416275864da4dbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 9 Feb 2023 18:50:05 +0100 Subject: [PATCH] Merge notification email logs into email archives --- modules/notification_email/CHANGELOG | 1 + modules/notification_email/__init__.py | 2 +- modules/notification_email/ir.py | 53 ++++++++++ modules/notification_email/ir.xml | 29 ++++++ modules/notification_email/notification.py | 99 +++---------------- modules/notification_email/notification.xml | 67 ------------- modules/notification_email/setup.py | 2 +- .../notification_email/tests/test_module.py | 39 ++++---- .../notification_email/view/ir_email_form.xml | 11 +++ modules/notification_email/view/log_form.xml | 19 ---- modules/notification_email/view/log_list.xml | 12 --- 11 files changed, 133 insertions(+), 201 deletions(-) create mode 100644 modules/notification_email/view/ir_email_form.xml delete mode 100644 modules/notification_email/view/log_form.xml delete mode 100644 modules/notification_email/view/log_list.xml diff --git a/modules/notification_email/CHANGELOG b/modules/notification_email/CHANGELOG index 1d5d82b8b7..2c37ee0bd0 100644 --- a/modules/notification_email/CHANGELOG +++ b/modules/notification_email/CHANGELOG @@ -1,3 +1,4 @@ +* Merge email logs into email archives * Remove support for Python 3.7 * Add support for Python 3.11 diff --git a/modules/notification_email/__init__.py b/modules/notification_email/__init__.py index 1b82d64baa..c0477d4c2f 100644 --- a/modules/notification_email/__init__.py +++ b/modules/notification_email/__init__.py @@ -8,7 +8,7 @@ from . import ir, notification def register(): Pool.register( ir.Trigger, + ir.Email, notification.Email, notification.EmailAttachment, - notification.EmailLog, module='notification_email', type_='model') diff --git a/modules/notification_email/ir.py b/modules/notification_email/ir.py index 3b1b306524..ddbb5b1dc1 100644 --- a/modules/notification_email/ir.py +++ b/modules/notification_email/ir.py @@ -1,8 +1,13 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. + +from sql import Table + +from trytond import backend from trytond.model import fields from trytond.pool import Pool, PoolMeta from trytond.pyson import Eval +from trytond.transaction import Transaction class Trigger(metaclass=PoolMeta): @@ -43,3 +48,51 @@ class Trigger(metaclass=PoolMeta): else: self.model = trigger_model self.action = 'notification.email|trigger' + + +class Email(metaclass=PoolMeta): + __name__ = 'ir.email' + + notification_email = fields.Many2One( + 'notification.email', "Notification Email", readonly=True, + states={ + 'invisible': ~Eval('notification_email'), + }) + notification_trigger = fields.Many2One( + 'ir.trigger', "Notification Trigger", readonly=True, + states={ + 'invisible': ~Eval('notification_trigger'), + }) + + @classmethod + def __register__(cls, module): + table = cls.__table__() + log = Table('notification_email_log') + + cursor = Transaction().connection.cursor() + + super().__register__(module) + + # Migration from 6.6: merge notification email log with email + if backend.TableHandler.table_exist('notification_email_log'): + query = table.insert( + [table.create_uid, table.create_date, + table.write_uid, table.write_date, + table.recipients, table.recipients_secondary, + table.recipients_hidden, + table.resource, + table.notification_email, table.notification_trigger], + log.select( + log.create_uid, log.create_date, + log.write_uid, log.write_date, + log.recipients, log.recipients_secondary, + log.recipients_hidden, + log.resource, + log.notification, log.trigger)) + cursor.execute(*query) + + def get_user(self, name): + user = super().get_user(name) + if self.notification_email or self.notification_trigger: + user = None + return user diff --git a/modules/notification_email/ir.xml b/modules/notification_email/ir.xml index b0cb69ffc3..cbee0e9953 100644 --- a/modules/notification_email/ir.xml +++ b/modules/notification_email/ir.xml @@ -8,5 +8,34 @@ this repository contains the full copyright notices and license terms. --> trigger_form + + + ir.email + + ir_email_form + + + + E-mails + ir.email + + + + + + + + + + + + + + form_relate + notification.email,-1 + + diff --git a/modules/notification_email/notification.py b/modules/notification_email/notification.py index 5bbb842645..d44f976417 100644 --- a/modules/notification_email/notification.py +++ b/modules/notification_email/notification.py @@ -9,12 +9,9 @@ from email.mime.nonmultipart import MIMENonMultipart from email.utils import formataddr, getaddresses, parseaddr from genshi.template import TextTemplate -from sql import Null -from sql.operators import Concat from trytond.config import config from trytond.i18n import gettext -from trytond.ir.resource import ResourceAccessMixin from trytond.model import ModelSQL, ModelView, fields from trytond.pool import Pool from trytond.pyson import Eval, TimeDelta @@ -202,17 +199,7 @@ class Email(ModelSQL, ModelView): msg['Cc'] = ', '.join(formataddr(parseaddr(a)) for a in cc) msg['Subject'] = Header(title, 'utf-8') msg['Auto-Submitted'] = 'auto-generated' - return msg - - def get_log(self, record, trigger, msg, bcc=None): - return { - 'recipients': msg['To'], - 'recipients_secondary': msg['Cc'], - 'recipients_hidden': bcc, - 'resource': str(record), - 'notification': trigger.notification_email.id, - 'trigger': trigger.id, - } + return msg, title @classmethod def trigger(cls, records, trigger): @@ -240,12 +227,12 @@ class Email(ModelSQL, ModelView): def send_email(self, records, trigger): pool = Pool() - Log = pool.get('notification.email.log') + Email = pool.get('ir.email') datamanager = SMTPDataManager() Transaction().join(datamanager) from_ = (config.get('notification_email', 'from') or config.get('email', 'from')) - logs = [] + emails = [] for record in records: to, to_languages = self._get_to(record) cc, cc_languages = self._get_cc(record) @@ -253,13 +240,20 @@ class Email(ModelSQL, ModelView): languagues = to_languages | cc_languages | bcc_languages to_addrs = [e for _, e in getaddresses(to + cc + bcc)] if to_addrs: - msg = self.get_email(record, from_, to, cc, bcc, languagues) + msg, title = self.get_email( + record, from_, to, cc, bcc, languagues) sendmail_transactional( from_, to_addrs, msg, datamanager=datamanager) - logs.append(self.get_log( - record, trigger, msg, bcc=', '.join(bcc))) - if logs: - Log.create(logs) + emails.append(Email( + recipients=', '.join(to), + recipients_secondary=', '.join(cc), + recipients_hidden=', '.join(bcc), + addresses=[{'address': a} for a in to_addrs], + subject=title, + resource=record, + notification_email=trigger.notification_email, + notification_trigger=trigger)) + Email.save(emails) def _get_recipients(self, record, name): if name == 'id': @@ -376,66 +370,3 @@ class EmailAttachment(ModelSQL): 'Content-Disposition', 'attachment', filename=('utf-8', language, name)) return msg - - -class EmailLog(ResourceAccessMixin, ModelSQL, ModelView): - "Notification Email Log" - __name__ = 'notification.email.log' - date = fields.Function(fields.DateTime('Date'), 'get_date') - recipients = fields.Char("Recipients") - recipients_secondary = fields.Char("Secondary Recipients") - recipients_hidden = fields.Char("Hidden Recipients") - notification = fields.Many2One( - 'notification.email', "Notification", - required=True, ondelete='RESTRICT') - trigger = fields.Many2One('ir.trigger', "Trigger") - - @classmethod - def __setup__(cls): - super().__setup__() - cls._order = [ - ('create_date', 'DESC'), - ('id', 'DESC'), - ] - - @classmethod - def __register__(cls, module_name): - pool = Pool() - Model = pool.get('ir.model') - Trigger = pool.get('ir.trigger') - model = Model.__table__() - trigger = Trigger.__table__() - table = cls.__table__() - super().__register__(module_name) - - table_h = cls.__table_handler__(module_name) - cursor = Transaction().connection.cursor() - - # Migration from 5.6: - # fill notification and resource - # remove required on trigger - notification = trigger.select( - trigger.notification_email, - where=trigger.id == table.trigger) - resource = (trigger - .join(model, condition=trigger.model == model.id) - .select( - Concat(model.model, ',-1'), - where=trigger.id == table.trigger)) - cursor.execute(*table.update( - [table.notification, table.resource], - [notification, resource], - where=(table.trigger != Null) & (table.resource == Null))) - table_h.not_null_action('trigger', 'remove') - - def get_date(self, name): - return self.create_date.replace(microsecond=0) - - @classmethod - def search_date(cls, name, clause): - return [('create_date',) + tuple(clause[1:])] - - @staticmethod - def order_date(tables): - table, _ = tables[None] - return [table.create_date] diff --git a/modules/notification_email/notification.xml b/modules/notification_email/notification.xml index f35891d773..1cc6e59837 100644 --- a/modules/notification_email/notification.xml +++ b/modules/notification_email/notification.xml @@ -55,72 +55,5 @@ this repository contains the full copyright notices and license terms. --> - - - notification.email.log - form - log_form - - - - notification.email.log - tree - log_list - - - - - - - - - - - - Logs - notification.email.log - - - - - - - - - - - - - - form_relate - notification.email,-1 - - - - - Notification E-Mails - notification.email.log - - - - - - - - - - - - - - form_relate - - diff --git a/modules/notification_email/setup.py b/modules/notification_email/setup.py index d005abbf3c..a40dc3af4c 100755 --- a/modules/notification_email/setup.py +++ b/modules/notification_email/setup.py @@ -41,7 +41,7 @@ else: download_url = 'http://downloads.tryton.org/%s.%s/' % ( major_version, minor_version) -requires = ['Genshi'] +requires = ['Genshi', 'python-sql'] for dep in info.get('depends', []): if not re.match(r'(ir|res)(\W|$)', dep): requires.append(get_require_version('trytond_%s' % dep)) diff --git a/modules/notification_email/tests/test_module.py b/modules/notification_email/tests/test_module.py index c50c2fb2c6..f13b0350d1 100644 --- a/modules/notification_email/tests/test_module.py +++ b/modules/notification_email/tests/test_module.py @@ -91,7 +91,7 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): Trigger = pool.get('ir.trigger') Model = pool.get('ir.model') NotificationEmail = pool.get('notification.email') - Log = pool.get('notification.email.log') + Email = pool.get('ir.email') self._setup_notification() notification_email, = NotificationEmail.search([]) @@ -99,7 +99,7 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): model, = Model.search([ ('model', '=', User.__name__), ]) - Trigger.create([{ + trigger, = Trigger.create([{ 'name': 'Test creation', 'model': model.id, 'on_create': True, @@ -111,7 +111,7 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): with patch.object( notification_module, 'sendmail_transactional') as sendmail, \ patch.object(notification_module, 'SMTPDataManager'): - User.create([{'name': "Michael Scott", 'login': "msc"}]) + user, = User.create([{'name': "Michael Scott", 'login': "msc"}]) self.run_tasks() sendmail.assert_called_once_with( FROM, ['user@example.com'], ANY, @@ -125,11 +125,14 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): self.assertEqual( msg.get_payload(0).get_payload(), 'Hello Michael Scott') - log, = Log.search([]) - self.assertEqual(log.trigger.notification_email, notification_email) - self.assertEqual(log.recipients, 'Administrator ') - self.assertEqual(log.recipients_secondary, '') - self.assertEqual(log.recipients_hidden, '') + email, = Email.search([]) + self.assertEqual(email.recipients, 'Administrator ') + self.assertEqual(email.recipients_secondary, '') + self.assertEqual(email.recipients_hidden, '') + self.assertEqual(email.subject, 'Notification Email') + self.assertEqual(email.resource, user) + self.assertEqual(email.notification_email, notification_email) + self.assertEqual(email.notification_trigger, trigger) @unittest.skipIf( (3, 5, 0) <= sys.version_info < (3, 5, 2), "python bug #25195") @@ -141,7 +144,7 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): Trigger = pool.get('ir.trigger') Model = pool.get('ir.model') NotificationEmail = pool.get('notification.email') - Log = pool.get('notification.email.log') + Email = pool.get('ir.email') self._setup_notification(recipient_field='id') notification_email, = NotificationEmail.search([]) @@ -149,7 +152,7 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): model, = Model.search([ ('model', '=', User.__name__), ]) - Trigger.create([{ + trigger, = Trigger.create([{ 'name': 'Test creation', 'model': model.id, 'on_create': True, @@ -161,7 +164,7 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): with patch.object( notification_module, 'sendmail_transactional') as sendmail, \ patch.object(notification_module, 'SMTPDataManager'): - User.create([{ + user, = User.create([{ 'name': "Michael Scott", 'login': "msc", 'email': 'msc@example.com'}]) @@ -170,9 +173,11 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): FROM, ['msc@example.com'], ANY, datamanager=ANY) - log, = Log.search([]) - self.assertEqual(log.trigger.notification_email, notification_email) - self.assertEqual(log.recipients, 'Michael Scott ') + email, = Email.search([]) + self.assertEqual(email.recipients, 'Michael Scott ') + self.assertEqual(email.resource, user) + self.assertEqual(email.notification_email, notification_email) + self.assertEqual(email.notification_trigger, trigger) @with_transaction() def test_notification_email_delay(self): @@ -240,7 +245,7 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): user, = User.create([{'name': "Michael Scott", 'login': "msc"}]) - msg = notification_email.get_email( + msg, title = notification_email.get_email( user, FROM, ['Administrator '], [], [], [en]) self.assertEqual(msg['From'], FROM) @@ -280,7 +285,7 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): user, = User.create([{'name': "Michael Scott", 'login': "msc"}]) - msg = notification_email.get_email( + msg, title = notification_email.get_email( user, FROM, ['Administrator '], [], [], [en]) self.assertEqual(msg['Subject'], 'Notification for Michael Scott') @@ -316,7 +321,7 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): 'language': es.id, }]) - msg = notification_email.get_email( + msg, title = notification_email.get_email( user, FROM, ['Administrator '], [], [], [es]) self.assertEqual(msg['Subject'], 'Notificación para Michael Scott') diff --git a/modules/notification_email/view/ir_email_form.xml b/modules/notification_email/view/ir_email_form.xml new file mode 100644 index 0000000000..14ac0a0f22 --- /dev/null +++ b/modules/notification_email/view/ir_email_form.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/modules/notification_email/view/log_form.xml b/modules/notification_email/view/log_form.xml deleted file mode 100644 index ee6bd732e6..0000000000 --- a/modules/notification_email/view/log_form.xml +++ /dev/null @@ -1,19 +0,0 @@ - - -
-