test_mail_group_moderation.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. from psycopg2 import IntegrityError
  4. from odoo import Command, tools
  5. from odoo.addons.mail_group.tests.data import GROUP_TEMPLATE
  6. from odoo.addons.mail_group.tests.common import TestMailListCommon
  7. from odoo.exceptions import AccessError
  8. from odoo.tests.common import tagged, users
  9. from odoo.tools import mute_logger
  10. @tagged('mail_group_moderation')
  11. class TestMailGroupModeration(TestMailListCommon):
  12. @classmethod
  13. def setUpClass(cls):
  14. super(TestMailGroupModeration, cls).setUpClass()
  15. cls.test_group_2 = cls.env['mail.group'].create({
  16. 'access_mode': 'members',
  17. 'alias_name': 'test.mail.group.2',
  18. 'moderation': True,
  19. 'moderator_ids': [Command.link(cls.user_employee.id)],
  20. 'name': 'Test group 2',
  21. })
  22. @mute_logger('odoo.sql_db')
  23. @users('employee')
  24. def test_constraints(self):
  25. mail_group = self.env['mail.group'].browse(self.test_group.ids)
  26. with self.assertRaises(IntegrityError):
  27. moderation = self.env['mail.group.moderation'].create({
  28. 'mail_group_id': mail_group.id,
  29. 'email': 'banned_member@test.com',
  30. 'status': 'ban',
  31. })
  32. @mute_logger('odoo.models.unlink', 'odoo.addons.mail_group.models.mail_group_message')
  33. @users('employee')
  34. def test_moderation_rule_api(self):
  35. """ Test moderation rule creation / update through API """
  36. mail_group = self.env['mail.group'].browse(self.test_group.ids)
  37. mail_group_2 = self.env['mail.group'].browse(self.test_group_2.ids)
  38. self.assertEqual(
  39. set(mail_group.moderation_rule_ids.mapped('email')),
  40. set(['banned_member@test.com'])
  41. )
  42. moderation_1, moderation_2, moderation_3 = self.env['mail.group.moderation'].create([{
  43. 'email': 'std@test.com',
  44. 'status': 'allow',
  45. 'mail_group_id': mail_group.id,
  46. }, {
  47. 'email': 'xss@test.com',
  48. 'status': 'ban',
  49. 'mail_group_id': mail_group.id,
  50. }, {
  51. 'email': 'xss@test.com',
  52. 'status': 'ban',
  53. 'mail_group_id': mail_group_2.id,
  54. }])
  55. self.assertEqual(
  56. set(mail_group.moderation_rule_ids.mapped('email')),
  57. set(['banned_member@test.com', 'std@test.com', 'xss@test.com'])
  58. )
  59. message_1, message_2, message_3 = self.env['mail.group.message'].create([{
  60. 'email_from': '"Boum" <sTd@teST.com>',
  61. 'mail_group_id': mail_group.id,
  62. }, {
  63. 'email_from': '"xSs" <xss@teST.com>',
  64. 'mail_group_id': mail_group.id,
  65. }, {
  66. 'email_from': '"Bob" <bob@teST.com>',
  67. 'mail_group_id': mail_group.id,
  68. }])
  69. # status 'bouh' does not exist
  70. with self.assertRaises(ValueError):
  71. (message_1 | message_2 | message_3)._create_moderation_rule('bouh')
  72. (message_1 | message_2 | message_3)._create_moderation_rule('allow')
  73. self.assertEqual(len(mail_group.moderation_rule_ids), 4, "Should have created only one moderation rule")
  74. self.assertEqual(
  75. set(mail_group.moderation_rule_ids.mapped('email')),
  76. set(['banned_member@test.com', 'std@test.com', 'xss@test.com', 'bob@test.com'])
  77. )
  78. self.assertEqual(moderation_1.status, 'allow')
  79. self.assertEqual(moderation_2.status, 'allow', 'Should have write on the existing moderation rule')
  80. self.assertEqual(moderation_3.status, 'ban', 'Should not have changed moderation of the other group')
  81. new_moderation = mail_group.moderation_rule_ids.filtered(lambda rule: rule.email == 'bob@test.com')
  82. self.assertEqual(new_moderation.status, 'allow', 'Should have created the moderation with the right status')
  83. @users('employee')
  84. def test_moderation_rule_email_normalize(self):
  85. """ Test emails are automatically normalized """
  86. rule = self.env['mail.group.moderation'].create({
  87. 'mail_group_id': self.test_group.id,
  88. 'email': '"Bob" <bob@test.com>',
  89. 'status': 'ban',
  90. })
  91. self.assertEqual(rule.email, 'bob@test.com')
  92. rule.email = '"Alice" <alice@test.com>'
  93. self.assertEqual(rule.email, 'alice@test.com')
  94. @mute_logger('odoo.addons.base.models.ir_rule', 'odoo.addons.base.models.ir_model')
  95. def test_moderation_rule_security(self):
  96. with self.assertRaises(AccessError, msg='Portal should not have access to moderation rules'):
  97. self.env['mail.group.moderation'].with_user(self.user_portal).browse(self.moderation.ids).email
  98. self.test_group.write({
  99. 'moderator_ids': [(4, self.user_admin.id), (3, self.user_employee.id)]
  100. })
  101. with self.assertRaises(AccessError, msg='Non moderators should not have access to moderation rules'):
  102. self.env['mail.group.moderation'].with_user(self.user_employee).browse(self.moderation.ids).email
  103. self.assertEqual(
  104. self.env['mail.group.moderation'].with_user(self.user_admin).browse(self.moderation.ids).email,
  105. 'banned_member@test.com',
  106. msg='Moderators should have access to moderation rules')
  107. @tagged('mail_group_moderation')
  108. class TestModeration(TestMailListCommon):
  109. @classmethod
  110. def setUpClass(cls):
  111. super(TestModeration, cls).setUpClass()
  112. # Test group: members, moderation
  113. cls.test_group_2 = cls.env['mail.group'].create({
  114. 'access_mode': 'members',
  115. 'alias_name': 'test.mail.group.2',
  116. 'moderation': True,
  117. 'moderator_ids': [Command.link(cls.user_employee.id)],
  118. 'name': 'Test group 2',
  119. })
  120. cls.test_group_2_member_emp = cls.env['mail.group.member'].create({
  121. 'partner_id': cls.user_employee_2.partner_id.id,
  122. 'email': cls.user_employee_2.email,
  123. 'mail_group_id': cls.test_group_2.id,
  124. })
  125. # Existing messages on group 2
  126. cls.test_group_2_msg_1_pending = cls.env['mail.group.message'].create({
  127. 'email_from': cls.email_from_unknown,
  128. 'subject': 'Group 2 Pending',
  129. 'mail_group_id': cls.test_group_2.id,
  130. 'moderation_status': 'pending_moderation',
  131. })
  132. @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.addons.mail_group.models.mail_group_message')
  133. @users('employee')
  134. def test_moderation_flow_accept(self):
  135. """ Unknown email sends email on moderated group, test accept """
  136. mail_group = self.env['mail.group'].browse(self.test_group.ids)
  137. self.assertEqual(len(mail_group.mail_group_message_ids), 3)
  138. with self.mock_mail_gateway():
  139. self.format_and_process(
  140. GROUP_TEMPLATE, self.email_from_unknown, self.test_group.alias_id.display_name,
  141. subject='Old email', target_model='mail.group')
  142. self.format_and_process(
  143. GROUP_TEMPLATE, self.email_from_unknown, self.test_group.alias_id.display_name,
  144. subject='New email', target_model='mail.group')
  145. # find messages
  146. self.assertEqual(len(mail_group.mail_group_message_ids), 5)
  147. old_email_message = mail_group.mail_group_message_ids[-2]
  148. new_email_message = mail_group.mail_group_message_ids[-1]
  149. # check message content
  150. self.assertEqual(old_email_message.moderation_status, 'pending_moderation')
  151. self.assertEqual(old_email_message.subject, 'Old email')
  152. self.assertEqual(new_email_message.moderation_status, 'pending_moderation')
  153. self.assertEqual(new_email_message.subject, 'New email')
  154. # accept email without any moderation rule
  155. with self.mock_mail_gateway():
  156. new_email_message.action_moderate_accept()
  157. self.assertEqual(len(self._new_mails), 4)
  158. for email in self.test_group_valid_members.mapped('email'):
  159. self.assertMailMailWEmails([email], 'outgoing',
  160. content="This should be posted on a mail.group. Or not.",
  161. fields_values={
  162. 'email_from': self.email_from_unknown,
  163. 'subject': 'New email',
  164. },
  165. mail_message=new_email_message.mail_message_id)
  166. self.assertEqual(new_email_message.moderation_status, 'accepted', 'Should have accepted the message')
  167. self.assertEqual(old_email_message.moderation_status, 'pending_moderation', 'Should not have touched other message of the same author')
  168. @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.addons.mail_group.models.mail_group_message', 'odoo.models.unlink')
  169. @users('employee')
  170. def test_moderation_flow_allow(self):
  171. """ Unknown email sends email on moderated group, test allow """
  172. mail_group = self.test_group
  173. mail_group_2_as2 = self.env['mail.group'].with_user(self.user_employee_2).browse(self.test_group_2.ids)
  174. self.assertEqual(len(mail_group.mail_group_message_ids), 3)
  175. group_2_message_count = len(mail_group_2_as2.mail_group_message_ids)
  176. with self.mock_mail_gateway():
  177. self.format_and_process(
  178. GROUP_TEMPLATE, self.email_from_unknown, self.test_group.alias_id.display_name,
  179. subject='Old email', target_model='mail.group')
  180. self.format_and_process(
  181. GROUP_TEMPLATE, self.email_from_unknown, self.test_group.alias_id.display_name,
  182. subject='New email', target_model='mail.group')
  183. # find messages
  184. self.assertEqual(len(mail_group.mail_group_message_ids), 5)
  185. old_email_message = mail_group.mail_group_message_ids[-2]
  186. new_email_message = mail_group.mail_group_message_ids[-1]
  187. # check message content
  188. self.assertEqual(old_email_message.email_from, self.email_from_unknown)
  189. self.assertEqual(old_email_message.moderation_status, 'pending_moderation')
  190. self.assertEqual(old_email_message.subject, 'Old email')
  191. self.assertEqual(new_email_message.email_from, self.email_from_unknown)
  192. self.assertEqual(new_email_message.moderation_status, 'pending_moderation')
  193. self.assertEqual(new_email_message.subject, 'New email')
  194. # Create a moderation rule to always accept this email address
  195. with self.mock_mail_gateway():
  196. new_email_message.action_moderate_allow()
  197. self.assertEqual(new_email_message.moderation_status, 'accepted', 'Should have accepted the message')
  198. self.assertEqual(old_email_message.moderation_status, 'accepted', 'Should have accepted the old message of the same author')
  199. # Test that the moderation rule has been created
  200. new_rule = self.env['mail.group.moderation'].search([
  201. ('status', '=', 'allow'),
  202. ('email', '=', tools.email_normalize(self.email_from_unknown))
  203. ])
  204. self.assertEqual(len(new_rule), 1, 'Should have created a moderation rule')
  205. # Check emails have been sent
  206. self.assertEqual(len(self._new_mails), 8)
  207. for email in self.test_group_valid_members.mapped('email'):
  208. self.assertMailMailWEmails([email], 'outgoing',
  209. content="This should be posted on a mail.group. Or not.",
  210. fields_values={
  211. 'email_from': self.email_from_unknown,
  212. 'subject': 'New email',
  213. },
  214. mail_message=new_email_message.mail_message_id)
  215. self.assertMailMailWEmails([email], 'outgoing',
  216. content="This should be posted on a mail.group. Or not.",
  217. fields_values={
  218. 'email_from': self.email_from_unknown,
  219. 'subject': 'Old email',
  220. },
  221. mail_message=old_email_message.mail_message_id)
  222. # Send a second email with the same FROM, but with a different name
  223. with self.mock_mail_gateway():
  224. self.format_and_process(
  225. GROUP_TEMPLATE,
  226. tools.formataddr(("Another Name", "bob.email@test.example.com")),
  227. self.test_group.alias_id.display_name,
  228. subject='Another email', target_model='mail.group')
  229. # find messages
  230. self.assertEqual(len(mail_group.mail_group_message_ids), 6)
  231. new_email_message = mail_group.mail_group_message_ids[-1]
  232. self.assertEqual(new_email_message.email_from, tools.formataddr(("Another Name", "bob.email@test.example.com")))
  233. self.assertEqual(new_email_message.moderation_status, 'accepted', msg='Should have automatically accepted the email')
  234. self.assertEqual(new_email_message.subject, 'Another email')
  235. self.assertEqual(
  236. self.test_group_2_msg_1_pending.moderation_status, 'pending_moderation',
  237. 'Should not have accepted message in the other group')
  238. self.assertEqual(
  239. len(mail_group_2_as2.mail_group_message_ids), group_2_message_count,
  240. 'Should never have created message in the other group')
  241. @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.addons.mail_group.models.mail_group_message', 'odoo.models.unlink')
  242. @users('employee')
  243. def test_moderation_flow_ban(self):
  244. """ Unknown email sends email on moderated group, test ban """
  245. mail_group = self.env['mail.group'].browse(self.test_group.ids)
  246. self.assertEqual(len(mail_group.mail_group_message_ids), 3)
  247. with self.mock_mail_gateway():
  248. self.format_and_process(
  249. GROUP_TEMPLATE, self.email_from_unknown, self.test_group.alias_id.display_name,
  250. subject='Old email', target_model='mail.group')
  251. self.format_and_process(
  252. GROUP_TEMPLATE, self.email_from_unknown, self.test_group.alias_id.display_name,
  253. subject='New email', target_model='mail.group')
  254. # find messages
  255. self.assertEqual(len(mail_group.mail_group_message_ids), 5)
  256. old_email_message = mail_group.mail_group_message_ids[-2]
  257. new_email_message = mail_group.mail_group_message_ids[-1]
  258. # ban and check moderation rule has been
  259. with self.mock_mail_gateway():
  260. new_email_message.action_moderate_ban()
  261. self.assertEqual(old_email_message.moderation_status, 'rejected')
  262. self.assertEqual(new_email_message.moderation_status, 'rejected')
  263. # Test that the moderation rule has been created
  264. new_rule = self.env['mail.group.moderation'].search([
  265. ('status', '=', 'ban'),
  266. ('email', '=', tools.email_normalize(self.email_from_unknown))
  267. ])
  268. self.assertEqual(len(new_rule), 1, 'Should have created a moderation rule')
  269. # Check no mail.mail has been sent
  270. self.assertEqual(len(self._new_mails), 0, 'Should not have send emails')
  271. # Send a second email with the same FROM, but with a different name
  272. with self.mock_mail_gateway():
  273. self.format_and_process(
  274. GROUP_TEMPLATE,
  275. tools.formataddr(("Another Name", "bob.email@test.example.com")),
  276. self.test_group.alias_id.display_name,
  277. subject='Another email', target_model='mail.group')
  278. # find messages
  279. self.assertEqual(len(mail_group.mail_group_message_ids), 6)
  280. new_email_message = mail_group.mail_group_message_ids[-1]
  281. self.assertEqual(new_email_message.moderation_status, 'rejected', 'Should have automatically rejected the email')
  282. # Check no mail.mail has been sent
  283. self.assertEqual(len(self._new_mails), 0, 'Should not have send emails')
  284. @mute_logger('odoo.addons.mail.models.mail_thread', 'odoo.addons.mail_group.models.mail_group_message', 'odoo.models.unlink')
  285. @users('employee')
  286. def test_moderation_flow_reject(self):
  287. """ Unknown email sends email on moderated group, test reject """
  288. mail_group = self.env['mail.group'].browse(self.test_group.ids)
  289. self.assertEqual(len(mail_group.mail_group_message_ids), 3)
  290. with self.mock_mail_gateway():
  291. self.format_and_process(
  292. GROUP_TEMPLATE, self.email_from_unknown, self.test_group.alias_id.display_name,
  293. subject='Old email', target_model='mail.group')
  294. self.format_and_process(
  295. GROUP_TEMPLATE, self.email_from_unknown, self.test_group.alias_id.display_name,
  296. subject='New email', target_model='mail.group')
  297. # find messages
  298. self.assertEqual(len(mail_group.mail_group_message_ids), 5)
  299. old_email_message = mail_group.mail_group_message_ids[-2]
  300. new_email_message = mail_group.mail_group_message_ids[-1]
  301. # reject without moderation rule
  302. with self.mock_mail_gateway():
  303. new_email_message.action_moderate_reject_with_comment('Test Rejected', 'Bad email')
  304. self.assertEqual(new_email_message.moderation_status, 'rejected', 'Should have rejected the message')
  305. self.assertEqual(old_email_message.moderation_status, 'pending_moderation', 'Should not have rejected old message')
  306. self.assertEqual(len(self._new_mails), 1, 'Should have sent the reject email')
  307. self.assertMailMailWEmails([self.email_from_unknown], 'outgoing',
  308. content="This should be posted on a mail.group. Or not.",
  309. fields_values={
  310. 'email_from': self.user_employee.email_formatted,
  311. 'subject': 'Test Rejected',
  312. })
  313. @mute_logger('odoo.addons.mail_group.models.mail_group')
  314. @users('employee')
  315. def test_moderation_send_guidelines(self):
  316. """ Test sending guidelines """
  317. mail_group = self.env['mail.group'].browse(self.test_group.ids)
  318. mail_group.write({
  319. 'moderation_guidelines': True,
  320. 'moderation_guidelines_msg': 'Test guidelines group',
  321. })
  322. with self.mock_mail_gateway():
  323. mail_group.action_send_guidelines()
  324. self.assertEqual(len(self._new_mails), 3)
  325. for email in self.test_group_valid_members.mapped('email'):
  326. self.assertMailMailWEmails([email], 'outgoing',
  327. content="Test guidelines group",
  328. fields_values={
  329. 'email_from': self.env.company.email_formatted,
  330. 'subject': 'Guidelines of group %s' % mail_group.name,
  331. })
  332. @mute_logger('odoo.addons.mail_group.models.mail_group')
  333. @users('employee')
  334. def test_moderation_send_guidelines_on_new_member(self):
  335. """ Test sending guidelines when having a new members """
  336. mail_group = self.env['mail.group'].browse(self.test_group.ids)
  337. mail_group.write({
  338. 'moderation_guidelines': True,
  339. 'moderation_guidelines_msg': 'Test guidelines group',
  340. })
  341. with self.mock_mail_gateway():
  342. mail_group._join_group('"New Member" <new.member@test.com>')
  343. self.assertEqual(len(self._new_mails), 1)
  344. self.assertMailMailWEmails(['"New Member" <new.member@test.com>'], 'outgoing',
  345. content="Test guidelines group",
  346. fields_values={
  347. 'email_from': self.env.company.email_formatted,
  348. 'subject': 'Guidelines of group %s' % mail_group.name,
  349. })