You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

245 lines
11 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2018 Tecnativa - Jairo Llopis
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. from contextlib import contextmanager
  5. from odoo.exceptions import ValidationError
  6. from odoo.tests.common import HttpCase
  7. class ActivityCase(HttpCase):
  8. def setUp(self):
  9. super(ActivityCase, self).setUp()
  10. # HACK https://github.com/odoo/odoo/issues/12237
  11. # TODO Remove hack in v12
  12. self._oldenv = self.env
  13. self.env = self._oldenv(self.cursor())
  14. # HACK end
  15. self.cron = self.env.ref("privacy_consent.cron_auto_consent")
  16. self.update_opt_out = self.env.ref("privacy_consent.update_opt_out")
  17. self.mt_consent_consent_new = self.env.ref(
  18. "privacy_consent.mt_consent_consent_new")
  19. self.mt_consent_acceptance_changed = self.env.ref(
  20. "privacy_consent.mt_consent_acceptance_changed")
  21. self.mt_consent_state_changed = self.env.ref(
  22. "privacy_consent.mt_consent_state_changed")
  23. # Some partners to ask for consent
  24. self.partners = self.env["res.partner"]
  25. self.partners += self.partners.create({
  26. "name": "consent-partner-0",
  27. "email": "partner0@example.com",
  28. "notify_email": "none",
  29. "opt_out": False,
  30. })
  31. self.partners += self.partners.create({
  32. "name": "consent-partner-1",
  33. "email": "partner1@example.com",
  34. "notify_email": "always",
  35. "opt_out": True,
  36. })
  37. self.partners += self.partners.create({
  38. "name": "consent-partner-2",
  39. "email": "partner2@example.com",
  40. "opt_out": False,
  41. })
  42. # Partner without email, on purpose
  43. self.partners += self.partners.create({
  44. "name": "consent-partner-3",
  45. "opt_out": True,
  46. })
  47. # Activity without consent
  48. self.activity_noconsent = self.env["privacy.activity"].create({
  49. "name": "activity_noconsent",
  50. "description": "I'm activity 1",
  51. })
  52. # Activity with auto consent, for all partners
  53. self.activity_auto = self.env["privacy.activity"].create({
  54. "name": "activity_auto",
  55. "description": "I'm activity auto",
  56. "subject_find": True,
  57. "subject_domain": repr([("id", "in", self.partners.ids)]),
  58. "consent_required": "auto",
  59. "default_consent": True,
  60. "server_action_id": self.update_opt_out.id,
  61. })
  62. # Activity with manual consent, skipping partner 0
  63. self.activity_manual = self.env["privacy.activity"].create({
  64. "name": "activity_manual",
  65. "description": "I'm activity 3",
  66. "subject_find": True,
  67. "subject_domain": repr([("id", "in", self.partners[1:].ids)]),
  68. "consent_required": "manual",
  69. "default_consent": False,
  70. "server_action_id": self.update_opt_out.id,
  71. })
  72. # HACK https://github.com/odoo/odoo/issues/12237
  73. # TODO Remove hack in v12
  74. def tearDown(self):
  75. self.env = self._oldenv
  76. super(ActivityCase, self).tearDown()
  77. # HACK https://github.com/odoo/odoo/issues/12237
  78. # TODO Remove hack in v12
  79. @contextmanager
  80. def release_cr(self):
  81. self.env.cr.release()
  82. yield
  83. self.env.cr.acquire()
  84. def check_activity_auto_properly_sent(self):
  85. """Check emails sent by ``self.activity_auto``."""
  86. consents = self.env["privacy.consent"].search([
  87. ("activity_id", "=", self.activity_auto.id),
  88. ])
  89. # Check sent mails
  90. for consent in consents:
  91. self.assertEqual(consent.state, "sent")
  92. messages = consent.mapped("message_ids")
  93. self.assertEqual(len(messages), 4)
  94. # 2nd message notifies creation
  95. self.assertEqual(
  96. messages[2].subtype_id,
  97. self.mt_consent_consent_new,
  98. )
  99. # 3rd message notifies subject
  100. # Placeholder links should be logged
  101. self.assertTrue("/privacy/consent/accept/" in messages[1].body)
  102. self.assertTrue("/privacy/consent/reject/" in messages[1].body)
  103. # Tokenized links shouldn't be logged
  104. self.assertFalse(consent._url(True) in messages[1].body)
  105. self.assertFalse(consent._url(False) in messages[1].body)
  106. # 4th message contains the state change
  107. self.assertEqual(
  108. messages[0].subtype_id,
  109. self.mt_consent_state_changed,
  110. )
  111. # Partner's opt_out should be synced with default consent
  112. self.assertFalse(consent.partner_id.opt_out)
  113. def test_default_template(self):
  114. """We have a good mail template by default."""
  115. good = self.env.ref("privacy_consent.template_consent")
  116. self.assertEqual(
  117. self.activity_noconsent.consent_template_id,
  118. good,
  119. )
  120. self.assertEqual(
  121. self.activity_noconsent.consent_template_default_body_html,
  122. good.body_html,
  123. )
  124. self.assertEqual(
  125. self.activity_noconsent.consent_template_default_subject,
  126. good.subject,
  127. )
  128. def test_find_subject_if_consent_required(self):
  129. """If user wants to require consent, it needs subjects."""
  130. # Test the onchange helper
  131. onchange_activity1 = self.env["privacy.activity"].new(
  132. self.activity_noconsent.copy_data()[0])
  133. self.assertFalse(onchange_activity1.subject_find)
  134. onchange_activity1.consent_required = "auto"
  135. onchange_activity1._onchange_consent_required_subject_find()
  136. self.assertTrue(onchange_activity1.subject_find)
  137. # Test very dumb user that forces an error
  138. with self.assertRaises(ValidationError):
  139. self.activity_noconsent.consent_required = "manual"
  140. def test_template_required_auto(self):
  141. """Automatic consent activities need a template."""
  142. self.activity_noconsent.subject_find = True
  143. self.activity_noconsent.consent_template_id = False
  144. self.activity_noconsent.consent_required = "manual"
  145. with self.assertRaises(ValidationError):
  146. self.activity_noconsent.consent_required = "auto"
  147. def test_generate_manually(self):
  148. """Manually-generated consents work as expected."""
  149. self.partners.write({"opt_out": False})
  150. result = self.activity_manual.action_new_consents()
  151. self.assertEqual(result["res_model"], "privacy.consent")
  152. consents = self.env[result["res_model"]].search(result["domain"])
  153. self.assertEqual(consents.mapped("state"), ["draft"] * 2)
  154. self.assertEqual(consents.mapped("partner_id.opt_out"), [False] * 2)
  155. self.assertEqual(consents.mapped("accepted"), [False] * 2)
  156. self.assertEqual(consents.mapped("last_metadata"), [False] * 2)
  157. # Check sent mails
  158. messages = consents.mapped("message_ids")
  159. self.assertEqual(len(messages), 4)
  160. subtypes = messages.mapped("subtype_id")
  161. self.assertTrue(subtypes & self.mt_consent_consent_new)
  162. self.assertFalse(subtypes & self.mt_consent_acceptance_changed)
  163. self.assertFalse(subtypes & self.mt_consent_state_changed)
  164. # Send one manual request
  165. action = consents[0].action_manual_ask()
  166. self.assertEqual(action["res_model"], "mail.compose.message")
  167. composer = self.env[action["res_model"]] \
  168. .with_context(active_ids=consents[0].ids,
  169. active_model=consents._name,
  170. **action["context"]).create({})
  171. composer.onchange_template_id_wrapper()
  172. composer.send_mail()
  173. messages = consents.mapped("message_ids") - messages
  174. self.assertEqual(len(messages), 2)
  175. self.assertEqual(messages[0].subtype_id, self.mt_consent_state_changed)
  176. self.assertEqual(consents.mapped("state"), ["sent", "draft"])
  177. self.assertEqual(consents.mapped("partner_id.opt_out"), [True, False])
  178. # Placeholder links should be logged
  179. self.assertTrue("/privacy/consent/accept/" in messages[1].body)
  180. self.assertTrue("/privacy/consent/reject/" in messages[1].body)
  181. # Tokenized links shouldn't be logged
  182. accept_url = consents[0]._url(True)
  183. reject_url = consents[0]._url(False)
  184. self.assertNotIn(accept_url, messages[1].body)
  185. self.assertNotIn(reject_url, messages[1].body)
  186. # Visit tokenized accept URL
  187. with self.release_cr():
  188. result = self.url_open(accept_url).read()
  189. self.assertIn("accepted", result)
  190. self.assertIn(reject_url, result)
  191. self.assertIn(self.activity_manual.name, result)
  192. self.assertIn(self.activity_manual.description, result)
  193. consents.invalidate_cache()
  194. self.assertEqual(consents.mapped("accepted"), [True, False])
  195. self.assertTrue(consents[0].last_metadata)
  196. self.assertFalse(consents[0].partner_id.opt_out)
  197. self.assertEqual(consents.mapped("state"), ["answered", "draft"])
  198. self.assertEqual(
  199. consents[0].message_ids[0].subtype_id,
  200. self.mt_consent_acceptance_changed,
  201. )
  202. # Visit tokenized reject URL
  203. with self.release_cr():
  204. result = self.url_open(reject_url).read()
  205. self.assertIn("rejected", result)
  206. self.assertIn(accept_url, result)
  207. self.assertIn(self.activity_manual.name, result)
  208. self.assertIn(self.activity_manual.description, result)
  209. consents.invalidate_cache()
  210. self.assertEqual(consents.mapped("accepted"), [False, False])
  211. self.assertTrue(consents[0].last_metadata)
  212. self.assertTrue(consents[0].partner_id.opt_out)
  213. self.assertEqual(consents.mapped("state"), ["answered", "draft"])
  214. self.assertEqual(
  215. consents[0].message_ids[0].subtype_id,
  216. self.mt_consent_acceptance_changed,
  217. )
  218. self.assertFalse(consents[1].last_metadata)
  219. def test_generate_automatically(self):
  220. """Automatically-generated consents work as expected."""
  221. result = self.activity_auto.action_new_consents()
  222. self.assertEqual(result["res_model"], "privacy.consent")
  223. self.check_activity_auto_properly_sent()
  224. def test_generate_cron(self):
  225. """Cron-generated consents work as expected."""
  226. self.cron.method_direct_trigger()
  227. self.check_activity_auto_properly_sent()
  228. def test_mail_template_without_links(self):
  229. """Cannot create mail template without needed links."""
  230. with self.assertRaises(ValidationError):
  231. self.activity_manual.consent_template_id.body_html = "No links :("