diff --git a/CHANGELOG b/CHANGELOG index 4a2bb2c614..b7dda5d9b6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Make warning check re-entrant * Manage DatabaseDataError in ModelSQL * Remove support for pysqlite2 * Do not import empty One2Many data diff --git a/doc/ref/transaction.rst b/doc/ref/transaction.rst index 19c4fe9c00..31d31fe238 100644 --- a/doc/ref/transaction.rst +++ b/doc/ref/transaction.rst @@ -35,6 +35,10 @@ Transaction .. attribute:: Transaction.trigger_records +.. attribute:: Transaction.check_warnings + + The set of warnings already checked. + .. attribute:: Transaction.timestamp .. attribute:: Transaction.started_at diff --git a/trytond/res/user.py b/trytond/res/user.py index 6e332d69a8..eed01a2757 100644 --- a/trytond/res/user.py +++ b/trytond/res/user.py @@ -1089,12 +1089,16 @@ class Warning_(ModelSQL, ModelView): context = transaction.context if not user or context.get('_skip_warnings'): return False + key = (user, warning_name) + if key in transaction.check_warnings: + return False warnings = cls.search([ ('user', '=', user), ('name', '=', warning_name), ]) if not warnings: return True + transaction.check_warnings.add(key) cls.delete([x for x in warnings if not x.always]) return False diff --git a/trytond/tests/test_res.py b/trytond/tests/test_res.py index 245ada09f7..776cf96457 100644 --- a/trytond/tests/test_res.py +++ b/trytond/tests/test_res.py @@ -8,6 +8,7 @@ except ImportError: PIL = None from trytond.pool import Pool +from trytond.transaction import Transaction from .test_tryton import ModuleTestCase, with_transaction @@ -29,6 +30,60 @@ class ResTestCase(ModuleTestCase): self.assertIsNotNone(user.avatar) self.assertRegex(user.avatar_url, r'/avatar/.*/([0-9a-fA-F]{12})') + @with_transaction() + def test_user_warning(self): + "Check user warning" + pool = Pool() + Warning_ = pool.get('res.user.warning') + + self.assertTrue(Warning_.check('test')) + + @with_transaction() + def test_user_warning_ignored(self): + "Check ignored user warning" + pool = Pool() + Warning_ = pool.get('res.user.warning') + + user_id = Transaction().user + Warning_.create([{ + 'user': user_id, + 'name': 'test', + }]) + + self.assertFalse(Warning_.check('test')) + self.assertFalse(Warning_.search([])) + + @with_transaction() + def test_user_warning_always_ignored(self): + "Check always ignored user warning" + pool = Pool() + Warning_ = pool.get('res.user.warning') + + user_id = Transaction().user + Warning_.create([{ + 'user': user_id, + 'name': 'test', + 'always': True, + }]) + + self.assertFalse(Warning_.check('test')) + self.assertTrue(Warning_.search([])) + + @with_transaction() + def test_user_warning_reentrant(self): + "Check re-entrant user warning" + pool = Pool() + Warning_ = pool.get('res.user.warning') + + user_id = Transaction().user + Warning_.create([{ + 'user': user_id, + 'name': 'test', + }]) + + self.assertFalse(Warning_.check('test')) + self.assertFalse(Warning_.check('test')) + def suite(): return unittest.TestLoader().loadTestsFromTestCase(ResTestCase) diff --git a/trytond/transaction.py b/trytond/transaction.py index 19e0507115..5605838962 100644 --- a/trytond/transaction.py +++ b/trytond/transaction.py @@ -62,6 +62,7 @@ class Transaction(object): create_records = None delete_records = None trigger_records = None + check_warnings = None timestamp = None started_at = None @@ -131,6 +132,7 @@ class Transaction(object): self.create_records = defaultdict(set) self.delete_records = defaultdict(set) self.trigger_records = defaultdict(set) + self.check_warnings = set() self.timestamp = {} self.counter = 0 self._datamanagers = []