udata 12.0.2.dev10__py3-none-any.whl → 13.0.1.dev21__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of udata might be problematic. Click here for more details.

Files changed (272) hide show
  1. udata/api/__init__.py +1 -0
  2. udata/api_fields.py +10 -4
  3. udata/app.py +11 -10
  4. udata/auth/__init__.py +9 -10
  5. udata/auth/mails.py +137 -45
  6. udata/auth/views.py +5 -12
  7. udata/commands/__init__.py +2 -4
  8. udata/commands/info.py +1 -3
  9. udata/commands/tests/test_fixtures.py +6 -3
  10. udata/core/access_type/api.py +18 -0
  11. udata/core/access_type/constants.py +98 -0
  12. udata/core/access_type/models.py +44 -0
  13. udata/core/activity/models.py +1 -1
  14. udata/core/badges/models.py +1 -1
  15. udata/core/badges/tasks.py +35 -1
  16. udata/core/badges/tests/test_commands.py +2 -4
  17. udata/core/badges/tests/test_model.py +2 -2
  18. udata/core/badges/tests/test_tasks.py +55 -0
  19. udata/core/constants.py +1 -0
  20. udata/core/contact_point/models.py +8 -0
  21. udata/core/dataservices/api.py +10 -12
  22. udata/core/dataservices/apiv2.py +3 -1
  23. udata/core/dataservices/constants.py +0 -29
  24. udata/core/dataservices/models.py +44 -44
  25. udata/core/dataservices/rdf.py +2 -1
  26. udata/core/dataservices/search.py +5 -9
  27. udata/core/dataservices/tasks.py +33 -0
  28. udata/core/dataset/api.py +15 -24
  29. udata/core/dataset/api_fields.py +11 -0
  30. udata/core/dataset/apiv2.py +11 -0
  31. udata/core/dataset/constants.py +0 -1
  32. udata/core/dataset/forms.py +29 -0
  33. udata/core/dataset/models.py +24 -42
  34. udata/core/dataset/rdf.py +2 -1
  35. udata/core/dataset/search.py +2 -2
  36. udata/core/dataset/tasks.py +86 -8
  37. udata/core/discussions/mails.py +63 -0
  38. udata/core/discussions/tasks.py +4 -18
  39. udata/core/metrics/__init__.py +0 -6
  40. udata/core/organization/api.py +20 -14
  41. udata/core/organization/mails.py +144 -0
  42. udata/core/organization/models.py +2 -1
  43. udata/core/organization/rdf.py +3 -3
  44. udata/core/organization/search.py +1 -1
  45. udata/core/organization/tasks.py +21 -49
  46. udata/core/pages/tests/test_api.py +0 -2
  47. udata/core/reuse/api.py +29 -3
  48. udata/core/reuse/mails.py +21 -0
  49. udata/core/reuse/models.py +10 -1
  50. udata/core/reuse/search.py +1 -1
  51. udata/core/reuse/tasks.py +2 -3
  52. udata/core/site/api.py +27 -19
  53. udata/core/site/models.py +2 -6
  54. udata/core/site/rdf.py +2 -2
  55. udata/core/spatial/tests/test_api.py +17 -20
  56. udata/core/spatial/tests/test_models.py +3 -3
  57. udata/core/user/mails.py +54 -0
  58. udata/core/user/models.py +2 -3
  59. udata/core/user/tasks.py +8 -23
  60. udata/core/user/tests/test_user_model.py +2 -6
  61. udata/entrypoints.py +0 -6
  62. udata/features/identicon/tests/test_backends.py +3 -13
  63. udata/forms/fields.py +3 -3
  64. udata/forms/widgets.py +2 -2
  65. udata/frontend/__init__.py +3 -32
  66. udata/harvest/actions.py +4 -9
  67. udata/harvest/api.py +5 -14
  68. udata/harvest/backends/__init__.py +20 -11
  69. udata/harvest/backends/base.py +2 -2
  70. udata/harvest/backends/ckan/harvesters.py +2 -1
  71. udata/harvest/backends/dcat.py +3 -0
  72. udata/harvest/backends/maaf.py +1 -0
  73. udata/harvest/commands.py +6 -4
  74. udata/harvest/forms.py +9 -6
  75. udata/harvest/tasks.py +3 -5
  76. udata/harvest/tests/ckan/test_ckan_backend.py +300 -337
  77. udata/harvest/tests/ckan/test_ckan_backend_errors.py +94 -99
  78. udata/harvest/tests/ckan/test_ckan_backend_filters.py +128 -122
  79. udata/harvest/tests/ckan/test_dkan_backend.py +39 -51
  80. udata/harvest/tests/dcat/bnodes.xml +17 -1
  81. udata/harvest/tests/dcat/datara--5a26b0f6-0ccf-46ad-ac58-734054b91977.rdf.xml +255 -0
  82. udata/harvest/tests/dcat/datara--f40c3860-7236-4b30-a141-23b8ae33f7b2.rdf.xml +289 -0
  83. udata/harvest/tests/factories.py +1 -1
  84. udata/harvest/tests/test_actions.py +11 -9
  85. udata/harvest/tests/test_api.py +4 -5
  86. udata/harvest/tests/test_base_backend.py +5 -4
  87. udata/harvest/tests/test_dcat_backend.py +72 -16
  88. udata/harvest/tests/test_models.py +2 -4
  89. udata/harvest/tests/test_notifications.py +2 -4
  90. udata/harvest/tests/test_tasks.py +2 -3
  91. udata/mail.py +90 -53
  92. udata/migrations/2025-01-05-dataservices-fields-changes.py +8 -14
  93. udata/migrations/2025-10-21-remove-ckan-harvest-modified-at.py +28 -0
  94. udata/migrations/2025-10-29-harvesters-sources-integrity.py +27 -0
  95. udata/models/__init__.py +0 -2
  96. udata/mongo/extras_fields.py +4 -3
  97. udata/mongo/taglist_field.py +3 -3
  98. udata/rdf.py +65 -20
  99. udata/sentry.py +3 -4
  100. udata/settings.py +15 -13
  101. udata/tags.py +5 -5
  102. udata/tasks.py +3 -3
  103. udata/templates/mail/message.html +65 -0
  104. udata/templates/mail/message.txt +16 -0
  105. udata/tests/__init__.py +40 -58
  106. udata/tests/api/__init__.py +87 -2
  107. udata/tests/api/test_activities_api.py +17 -23
  108. udata/tests/api/test_auth_api.py +2 -4
  109. udata/tests/api/test_contact_points.py +48 -54
  110. udata/tests/api/test_dataservices_api.py +65 -97
  111. udata/tests/api/test_datasets_api.py +171 -56
  112. udata/tests/api/test_me_api.py +4 -6
  113. udata/tests/api/test_organizations_api.py +19 -38
  114. udata/tests/api/test_reports_api.py +0 -4
  115. udata/tests/api/test_reuses_api.py +99 -23
  116. udata/tests/api/test_security_api.py +124 -0
  117. udata/tests/api/test_swagger.py +2 -3
  118. udata/tests/api/test_tags_api.py +6 -7
  119. udata/tests/api/test_transfer_api.py +0 -2
  120. udata/tests/api/test_user_api.py +8 -10
  121. udata/tests/apiv2/test_datasets.py +0 -4
  122. udata/tests/apiv2/test_me_api.py +0 -2
  123. udata/tests/apiv2/test_organizations.py +0 -2
  124. udata/tests/apiv2/test_swagger.py +2 -3
  125. udata/tests/apiv2/test_topics.py +0 -2
  126. udata/tests/cli/test_cli_base.py +14 -12
  127. udata/tests/cli/test_db_cli.py +51 -54
  128. udata/tests/contact_point/test_contact_point_models.py +2 -2
  129. udata/tests/dataservice/test_csv_adapter.py +2 -5
  130. udata/tests/dataservice/test_dataservice_rdf.py +64 -4
  131. udata/tests/dataservice/test_dataservice_tasks.py +36 -38
  132. udata/tests/dataset/test_csv_adapter.py +2 -5
  133. udata/tests/dataset/test_dataset_actions.py +2 -4
  134. udata/tests/dataset/test_dataset_commands.py +2 -4
  135. udata/tests/dataset/test_dataset_events.py +3 -3
  136. udata/tests/dataset/test_dataset_model.py +6 -7
  137. udata/tests/dataset/test_dataset_rdf.py +205 -16
  138. udata/tests/dataset/test_dataset_recommendations.py +2 -2
  139. udata/tests/dataset/test_dataset_tasks.py +66 -68
  140. udata/tests/dataset/test_resource_preview.py +39 -48
  141. udata/tests/dataset/test_transport_tasks.py +2 -2
  142. udata/tests/features/territories/__init__.py +0 -6
  143. udata/tests/features/territories/test_territories_api.py +25 -24
  144. udata/tests/forms/test_current_user_field.py +2 -2
  145. udata/tests/forms/test_dict_field.py +2 -4
  146. udata/tests/forms/test_extras_fields.py +2 -3
  147. udata/tests/forms/test_image_field.py +2 -2
  148. udata/tests/forms/test_model_field.py +2 -4
  149. udata/tests/forms/test_publish_as_field.py +2 -4
  150. udata/tests/forms/test_user_forms.py +26 -29
  151. udata/tests/frontend/test_auth.py +2 -3
  152. udata/tests/frontend/test_csv.py +5 -6
  153. udata/tests/frontend/test_error_handlers.py +2 -3
  154. udata/tests/frontend/test_hooks.py +5 -7
  155. udata/tests/frontend/test_markdown.py +3 -4
  156. udata/tests/helpers.py +2 -7
  157. udata/tests/metrics/test_metrics.py +52 -48
  158. udata/tests/metrics/test_tasks.py +154 -150
  159. udata/tests/organization/test_csv_adapter.py +2 -5
  160. udata/tests/organization/test_notifications.py +2 -4
  161. udata/tests/organization/test_organization_model.py +3 -4
  162. udata/tests/organization/test_organization_rdf.py +6 -12
  163. udata/tests/plugin.py +6 -110
  164. udata/tests/reuse/test_reuse_model.py +3 -4
  165. udata/tests/site/test_site_api.py +0 -2
  166. udata/tests/site/test_site_csv_exports.py +0 -2
  167. udata/tests/site/test_site_metrics.py +2 -4
  168. udata/tests/site/test_site_model.py +2 -2
  169. udata/tests/site/test_site_rdf.py +85 -29
  170. udata/tests/test_activity.py +3 -3
  171. udata/tests/test_api_fields.py +6 -9
  172. udata/tests/test_cors.py +0 -2
  173. udata/tests/test_dcat_commands.py +2 -3
  174. udata/tests/test_discussions.py +2 -7
  175. udata/tests/test_mail.py +150 -114
  176. udata/tests/test_migrations.py +413 -419
  177. udata/tests/test_model.py +10 -11
  178. udata/tests/test_notifications.py +2 -3
  179. udata/tests/test_owned.py +3 -3
  180. udata/tests/test_rdf.py +19 -15
  181. udata/tests/test_routing.py +5 -5
  182. udata/tests/test_storages.py +6 -5
  183. udata/tests/test_tags.py +2 -4
  184. udata/tests/test_topics.py +2 -4
  185. udata/tests/test_transfer.py +4 -5
  186. udata/tests/topic/test_topic_tasks.py +25 -27
  187. udata/tests/user/test_user_rdf.py +2 -8
  188. udata/tests/user/test_user_tasks.py +3 -5
  189. udata/tests/workers/test_jobs_commands.py +2 -2
  190. udata/tests/workers/test_tasks_routing.py +27 -27
  191. udata/translations/ar/LC_MESSAGES/udata.mo +0 -0
  192. udata/translations/ar/LC_MESSAGES/udata.po +369 -435
  193. udata/translations/de/LC_MESSAGES/udata.mo +0 -0
  194. udata/translations/de/LC_MESSAGES/udata.po +371 -437
  195. udata/translations/es/LC_MESSAGES/udata.mo +0 -0
  196. udata/translations/es/LC_MESSAGES/udata.po +369 -435
  197. udata/translations/fr/LC_MESSAGES/udata.mo +0 -0
  198. udata/translations/fr/LC_MESSAGES/udata.po +381 -447
  199. udata/translations/it/LC_MESSAGES/udata.mo +0 -0
  200. udata/translations/it/LC_MESSAGES/udata.po +371 -437
  201. udata/translations/pt/LC_MESSAGES/udata.mo +0 -0
  202. udata/translations/pt/LC_MESSAGES/udata.po +371 -437
  203. udata/translations/sr/LC_MESSAGES/udata.mo +0 -0
  204. udata/translations/sr/LC_MESSAGES/udata.po +372 -438
  205. udata/translations/udata.pot +379 -440
  206. udata/utils.py +66 -4
  207. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/METADATA +1 -4
  208. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/RECORD +212 -256
  209. udata/linkchecker/__init__.py +0 -0
  210. udata/linkchecker/backends.py +0 -31
  211. udata/linkchecker/checker.py +0 -75
  212. udata/linkchecker/commands.py +0 -21
  213. udata/linkchecker/models.py +0 -9
  214. udata/linkchecker/tasks.py +0 -55
  215. udata/templates/mail/account_deleted.html +0 -5
  216. udata/templates/mail/account_deleted.txt +0 -6
  217. udata/templates/mail/account_inactivity.html +0 -40
  218. udata/templates/mail/account_inactivity.txt +0 -31
  219. udata/templates/mail/badge_added_association.html +0 -33
  220. udata/templates/mail/badge_added_association.txt +0 -11
  221. udata/templates/mail/badge_added_certified.html +0 -33
  222. udata/templates/mail/badge_added_certified.txt +0 -11
  223. udata/templates/mail/badge_added_company.html +0 -33
  224. udata/templates/mail/badge_added_company.txt +0 -11
  225. udata/templates/mail/badge_added_local_authority.html +0 -33
  226. udata/templates/mail/badge_added_local_authority.txt +0 -11
  227. udata/templates/mail/badge_added_public_service.html +0 -33
  228. udata/templates/mail/badge_added_public_service.txt +0 -11
  229. udata/templates/mail/discussion_closed.html +0 -47
  230. udata/templates/mail/discussion_closed.txt +0 -16
  231. udata/templates/mail/inactive_account_deleted.html +0 -5
  232. udata/templates/mail/inactive_account_deleted.txt +0 -6
  233. udata/templates/mail/membership_refused.html +0 -20
  234. udata/templates/mail/membership_refused.txt +0 -11
  235. udata/templates/mail/membership_request.html +0 -46
  236. udata/templates/mail/membership_request.txt +0 -12
  237. udata/templates/mail/new_discussion.html +0 -44
  238. udata/templates/mail/new_discussion.txt +0 -15
  239. udata/templates/mail/new_discussion_comment.html +0 -45
  240. udata/templates/mail/new_discussion_comment.txt +0 -16
  241. udata/templates/mail/new_member.html +0 -27
  242. udata/templates/mail/new_member.txt +0 -11
  243. udata/templates/mail/new_reuse.html +0 -37
  244. udata/templates/mail/new_reuse.txt +0 -9
  245. udata/templates/mail/test.html +0 -6
  246. udata/templates/mail/test.txt +0 -6
  247. udata/templates/mail/user_mail_card.html +0 -26
  248. udata/templates/security/email/base.html +0 -105
  249. udata/templates/security/email/base.txt +0 -6
  250. udata/templates/security/email/button.html +0 -3
  251. udata/templates/security/email/change_notice.html +0 -22
  252. udata/templates/security/email/change_notice.txt +0 -8
  253. udata/templates/security/email/confirmation_instructions.html +0 -20
  254. udata/templates/security/email/confirmation_instructions.txt +0 -7
  255. udata/templates/security/email/login_instructions.html +0 -19
  256. udata/templates/security/email/login_instructions.txt +0 -7
  257. udata/templates/security/email/reset_instructions.html +0 -24
  258. udata/templates/security/email/reset_instructions.txt +0 -9
  259. udata/templates/security/email/reset_notice.html +0 -11
  260. udata/templates/security/email/reset_notice.txt +0 -4
  261. udata/templates/security/email/welcome.html +0 -24
  262. udata/templates/security/email/welcome.txt +0 -9
  263. udata/templates/security/email/welcome_existing.html +0 -32
  264. udata/templates/security/email/welcome_existing.txt +0 -14
  265. udata/terms.md +0 -6
  266. udata/tests/frontend/__init__.py +0 -23
  267. udata/tests/metrics/conftest.py +0 -15
  268. udata/tests/test_linkchecker.py +0 -277
  269. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/WHEEL +0 -0
  270. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/entry_points.txt +0 -0
  271. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/licenses/LICENSE +0 -0
  272. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/top_level.txt +0 -0
udata/tests/test_mail.py CHANGED
@@ -1,120 +1,156 @@
1
- from contextlib import contextmanager
2
- from smtplib import SMTPRecipientsRefused
3
-
4
1
  import pytest
5
2
 
6
3
  from udata.core.organization.factories import OrganizationFactory
7
4
  from udata.core.user.factories import UserFactory
8
- from udata.mail import mail, mail_sent, send
9
- from udata.tests import DBTestMixin, TestCase
10
- from udata.tests.helpers import assert_emit, assert_not_emit
11
-
12
- SMTPRecipientsRefusedList = ["not-found@udata", "not-found-either@udata"]
13
-
14
-
15
- class FakeSender:
16
- def send(self, msg):
17
- if all(recipient in SMTPRecipientsRefusedList for recipient in msg.recipients):
18
- raise SMTPRecipientsRefused(msg.recipients)
19
- mail_sent.send(msg)
20
-
21
-
22
- class FakeMail:
23
- @contextmanager
24
- def connect(*args, **kw):
25
- yield FakeSender()
26
-
27
-
28
- class MailSendTest(TestCase, DBTestMixin):
29
- def create_app(self):
30
- app = super().create_app()
31
- app.config["SEND_MAIL"] = True
32
- return app
33
-
34
- @pytest.fixture(autouse=True)
35
- def patch_mail(self, mocker):
36
- mocker.patch("udata.mail.mail", FakeMail())
37
-
38
- def test_send_mail(self):
39
- with assert_emit(mail_sent):
40
- send("subject", [UserFactory(email="recipient@udata")], "base")
41
-
42
- def test_send_mail_to_not_found_recipients(self):
43
- with assert_not_emit(mail_sent):
44
- send("subject", [UserFactory(email="not-found@udata")], "base")
45
-
46
- def test_send_mail_to_multiple_recipients_with_some_not_found(self):
47
- recipients = [
48
- UserFactory(email="not-found@udata"),
49
- UserFactory(email="recipient@udata"),
50
- UserFactory(email="not-found-either@udata"),
51
- ]
52
- with assert_emit(mail_sent):
53
- send("subject", recipients, "base")
54
-
55
-
56
- @pytest.mark.usefixtures("clean_db")
57
- @pytest.mark.frontend
58
- class MailCampaignTest:
59
- def test_send_mail_campaign_link_new_member(self, app):
60
- # MTM campaign are only added on web URL (not API ones generated when
61
- # no front-end is configured)
62
- app.config["CDATA_BASE_URL"] = "https://www.data.gouv.fr"
63
-
64
- org = OrganizationFactory()
65
- recipient = UserFactory(email="recipient@udata")
66
-
67
- app.config["SEND_MAIL"] = True
68
- app.config["MAIL_CAMPAIGN"] = ""
69
- with mail.record_messages() as outbox:
70
- send(
71
- "subject",
72
- [recipient],
73
- "new_member",
74
- org=org,
5
+ from udata.i18n import lazy_gettext as _
6
+ from udata.mail import LabelledContent, MailMessage, ParagraphWithLinks, send_mail
7
+ from udata.tests.api import APITestCase
8
+ from udata.tests.helpers import capture_mails
9
+
10
+
11
+ class MailGenerationTest(APITestCase):
12
+ @pytest.mark.options(DEFAULT_LANGUAGE="en")
13
+ def test_simple_mail(self):
14
+ with capture_mails() as mails:
15
+ send_mail(
16
+ UserFactory(email="jane@example.org"),
17
+ MailMessage(_("Unknown"), paragraphs=[_("Some text")]),
18
+ )
19
+
20
+ assert len(mails) == 1
21
+ assert len(mails[0].recipients) == 1
22
+ assert mails[0].recipients[0] == "jane@example.org"
23
+ assert mails[0].subject == "Unknown"
24
+ assert "Some text" in mails[0].body
25
+ assert "Some text" in mails[0].html
26
+
27
+ @pytest.mark.options(DEFAULT_LANGUAGE="en")
28
+ def test_allow_none_in_paragraphs(self):
29
+ with capture_mails() as mails:
30
+ send_mail(
31
+ UserFactory(email="jane@example.org"),
32
+ MailMessage(_("Unknown"), paragraphs=[_("Some text"), None]),
75
33
  )
76
- assert len(outbox) == 1
77
- message = outbox[0]
78
- assert "mtm_campaign" not in message.body
79
- assert "mtm_campaign" not in message.html
80
-
81
- app.config["MAIL_CAMPAIGN"] = "data-gouv-fr"
82
- with mail.record_messages() as outbox:
83
- send(
84
- "subject",
85
- [recipient],
86
- "new_member",
87
- org=org,
34
+
35
+ assert len(mails) == 1
36
+
37
+ @pytest.mark.options(DEFAULT_LANGUAGE="en")
38
+ def test_multiple_recipients(self):
39
+ with capture_mails() as mails:
40
+ send_mail(
41
+ [
42
+ UserFactory(email="jane@example.org"),
43
+ UserFactory(email="john@example.org", prefered_language="fr"),
44
+ ],
45
+ MailMessage(_("Unknown"), paragraphs=[_("Some text")]),
46
+ )
47
+
48
+ assert len(mails) == 2
49
+ assert len(mails[0].recipients) == 1
50
+ assert mails[0].recipients[0] == "jane@example.org"
51
+ assert mails[0].subject == "Unknown"
52
+ assert len(mails[1].recipients) == 1
53
+ assert mails[1].recipients[0] == "john@example.org"
54
+ assert mails[1].subject == "Inconnu"
55
+
56
+ @pytest.mark.options(DEFAULT_LANGUAGE="en")
57
+ def test_use_user_language(self):
58
+ with capture_mails() as mails:
59
+ send_mail(
60
+ UserFactory(email="jane@example.org", prefered_language="fr"),
61
+ MailMessage(_("Unknown"), paragraphs=[_("Some text")]),
88
62
  )
89
- assert len(outbox) == 1
90
- message = outbox[0]
91
- assert "mtm_campaign=data-gouv-fr" in message.body
92
- assert "mtm_campaign=data-gouv-fr" in message.html
93
-
94
- def test_send_mail_campaign_link_badge_added_company(self, app):
95
- # MTM campaign are only added on web URL (not API ones generated when
96
- # no front-end is configured)
97
- app.config["CDATA_BASE_URL"] = "https://www.data.gouv.fr"
98
-
99
- app.config["SEND_MAIL"] = True
100
- org = OrganizationFactory()
101
- org.add_badge("company")
102
- badge = org.badges[0]
103
- badge.created_by = UserFactory()
104
- recipient = UserFactory(email="recipient@udata")
105
-
106
- app.config["MAIL_CAMPAIGN"] = ""
107
- with mail.record_messages() as outbox:
108
- send("subject", [recipient], "badge_added_company", organization=org, badge=badge)
109
- assert len(outbox) == 1
110
- message = outbox[0]
111
- assert "mtm_campaign" not in message.body
112
- assert "mtm_campaign" not in message.html
113
-
114
- app.config["MAIL_CAMPAIGN"] = "data-gouv-fr"
115
- with mail.record_messages() as outbox:
116
- send("subject", [recipient], "badge_added_company", organization=org, badge=badge)
117
- assert len(outbox) == 1
118
- message = outbox[0]
119
- assert "mtm_campaign=data-gouv-fr" in message.body
120
- assert "mtm_campaign=data-gouv-fr" in message.html
63
+
64
+ assert len(mails) == 1
65
+ assert mails[0].subject == "Inconnu"
66
+
67
+ @pytest.mark.options(DEFAULT_LANGUAGE="en")
68
+ def test_use_objects_in_translations(self):
69
+ org = OrganizationFactory(name="My Org")
70
+
71
+ with capture_mails() as mails:
72
+ send_mail(
73
+ UserFactory(email="jane@example.org", prefered_language="fr"),
74
+ MailMessage(
75
+ _("Unknown"),
76
+ paragraphs=[ParagraphWithLinks(_("Some text %(org)s", org=org))],
77
+ ),
78
+ )
79
+
80
+ assert len(mails) == 1
81
+ assert "My Org" in mails[0].body
82
+ assert org.url_for() not in mails[0].body
83
+ assert "My Org" in mails[0].html
84
+ assert "<a" in mails[0].html
85
+ assert org.url_for() in mails[0].html
86
+
87
+ @pytest.mark.options(DEFAULT_LANGUAGE="en")
88
+ def test_labelled_bloc(self):
89
+ with capture_mails() as mails:
90
+ send_mail(
91
+ UserFactory(email="jane@example.org", prefered_language="fr"),
92
+ MailMessage(
93
+ _("Unknown"),
94
+ paragraphs=[LabelledContent(_("Some text:"), "Some content", inline=True)],
95
+ ),
96
+ )
97
+
98
+ assert len(mails) == 1
99
+ assert "<strong>Du texte :</strong> Some content" in mails[0].html
100
+ assert "Du texte : Some content" in mails[0].body
101
+
102
+ @pytest.mark.options(DEFAULT_LANGUAGE="en")
103
+ def test_labelled_bloc_truncation(self):
104
+ with capture_mails() as mails:
105
+ send_mail(
106
+ UserFactory(email="jane@example.org", prefered_language="fr"),
107
+ MailMessage(
108
+ _("Unknown"),
109
+ paragraphs=[
110
+ LabelledContent(
111
+ _("Some text:"),
112
+ """
113
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
114
+ """,
115
+ )
116
+ ],
117
+ ),
118
+ )
119
+
120
+ assert len(mails) == 1
121
+ assert "a type specimen book." not in mails[0].html
122
+ assert "a type specimen book." not in mails[0].body
123
+
124
+ @pytest.mark.options(DEFAULT_LANGUAGE="en")
125
+ def test_escape_user_content_in_content(self):
126
+ with capture_mails() as mails:
127
+ send_mail(
128
+ UserFactory(email="jane@example.org", prefered_language="fr"),
129
+ MailMessage(
130
+ _("Unknown"),
131
+ paragraphs=[
132
+ LabelledContent(
133
+ _("Some text:"), "<script>Some content</script>", inline=True
134
+ )
135
+ ],
136
+ ),
137
+ )
138
+
139
+ assert len(mails) == 1
140
+ assert "<script>" not in mails[0].html
141
+
142
+ @pytest.mark.options(DEFAULT_LANGUAGE="en")
143
+ def test_escape_user_content_in_object_label(self):
144
+ org = OrganizationFactory(name="<script>My Org</script>")
145
+
146
+ with capture_mails() as mails:
147
+ send_mail(
148
+ UserFactory(email="jane@example.org", prefered_language="fr"),
149
+ MailMessage(
150
+ _("Unknown"),
151
+ paragraphs=[ParagraphWithLinks(_("Some text %(org)s", org=org))],
152
+ ),
153
+ )
154
+
155
+ assert len(mails) == 1
156
+ assert "<script>" not in mails[0].html