django-pfx 1.7.3.dev4__tar.gz → 1.7.3.dev8__tar.gz

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.
Files changed (261) hide show
  1. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/.pre-commit-config.yaml +8 -8
  2. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/PKG-INFO +4 -1
  3. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/django_pfx.egg-info/PKG-INFO +4 -1
  4. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/django_pfx.egg-info/SOURCES.txt +52 -0
  5. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/django_pfx.egg-info/requires.txt +4 -0
  6. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/conf.py +3 -1
  7. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/make_messages +1 -0
  8. django_pfx-1.7.3.dev8/pfx/emails/__init__.py +1 -0
  9. django_pfx-1.7.3.dev8/pfx/emails/apps.py +14 -0
  10. django_pfx-1.7.3.dev8/pfx/emails/email_backend/__init__.py +1 -0
  11. django_pfx-1.7.3.dev8/pfx/emails/email_backend/q_mailjet_email_backend.py +96 -0
  12. django_pfx-1.7.3.dev8/pfx/emails/exceptions.py +2 -0
  13. django_pfx-1.7.3.dev8/pfx/emails/mailjet/__init__.py +2 -0
  14. django_pfx-1.7.3.dev8/pfx/emails/mailjet/mailjet.py +18 -0
  15. django_pfx-1.7.3.dev8/pfx/emails/mailjet/message_result.py +32 -0
  16. django_pfx-1.7.3.dev8/pfx/emails/migrations/0001_initial.py +47 -0
  17. django_pfx-1.7.3.dev8/pfx/emails/migrations/0002_alter_email_headers.py +19 -0
  18. django_pfx-1.7.3.dev8/pfx/emails/migrations/0003_alter_email_options.py +18 -0
  19. django_pfx-1.7.3.dev8/pfx/emails/models/__init__.py +1 -0
  20. django_pfx-1.7.3.dev8/pfx/emails/models/email.py +378 -0
  21. django_pfx-1.7.3.dev8/pfx/emails/providers/__init__.py +1 -0
  22. django_pfx-1.7.3.dev8/pfx/emails/providers/email_django_q_executor.py +64 -0
  23. django_pfx-1.7.3.dev8/pfx/emails/shortcuts.py +117 -0
  24. django_pfx-1.7.3.dev8/pfx/emails/tasks.py +46 -0
  25. django_pfx-1.7.3.dev8/pfx/emails/templates/emails/base_template.html +89 -0
  26. django_pfx-1.7.3.dev8/pfx/emails/templates/emails/base_template.txt +7 -0
  27. django_pfx-1.7.3.dev8/pfx/emails/templates/emails/base_template_subject.txt +3 -0
  28. django_pfx-1.7.3.dev8/pfx/emails/urls.py +7 -0
  29. django_pfx-1.7.3.dev8/pfx/emails/views/__init__.py +1 -0
  30. django_pfx-1.7.3.dev8/pfx/emails/views/email_rest_view.py +44 -0
  31. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/__init__.py +0 -2
  32. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/apps.py +15 -1
  33. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/default_settings.py +7 -0
  34. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/fields/media_field.py +19 -1
  35. django_pfx-1.7.3.dev8/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  36. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +26 -12
  37. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/__init__.py +1 -0
  38. django_pfx-1.7.3.dev8/pfx/pfxcore/models/attachment_mixin.py +78 -0
  39. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/ordered_model_mixin.py +2 -1
  40. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/shortcuts.py +5 -0
  41. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/templates/registration/otp_code_email.txt +1 -1
  42. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/templates/registration/password_reset_email.txt +2 -2
  43. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/templates/registration/welcome_email.txt +1 -1
  44. django_pfx-1.7.3.dev8/pfx/settings/dev.py +35 -0
  45. django_pfx-1.7.3.dev8/pfx/userjobs/__init__.py +1 -0
  46. django_pfx-1.7.3.dev8/pfx/userjobs/apps.py +18 -0
  47. django_pfx-1.7.3.dev8/pfx/userjobs/locale/fr/LC_MESSAGES/django.mo +0 -0
  48. django_pfx-1.7.3.dev8/pfx/userjobs/locale/fr/LC_MESSAGES/django.po +154 -0
  49. django_pfx-1.7.3.dev8/pfx/userjobs/migrations/0001_initial.py +76 -0
  50. django_pfx-1.7.3.dev8/pfx/userjobs/migrations/0002_alter_userjob_options_alter_userjob_auto_queued_and_more.py +100 -0
  51. django_pfx-1.7.3.dev8/pfx/userjobs/models/__init__.py +2 -0
  52. django_pfx-1.7.3.dev8/pfx/userjobs/models/user_job.py +217 -0
  53. django_pfx-1.7.3.dev8/pfx/userjobs/models/user_job_attachment.py +32 -0
  54. django_pfx-1.7.3.dev8/pfx/userjobs/providers/__init__.py +4 -0
  55. django_pfx-1.7.3.dev8/pfx/userjobs/providers/user_job_django_q_executor.py +49 -0
  56. django_pfx-1.7.3.dev8/pfx/userjobs/providers/user_job_websocket_channel_provider.py +30 -0
  57. django_pfx-1.7.3.dev8/pfx/userjobs/tasks.py +72 -0
  58. django_pfx-1.7.3.dev8/pfx/userjobs/urls.py +14 -0
  59. django_pfx-1.7.3.dev8/pfx/userjobs/views/__init__.py +3 -0
  60. django_pfx-1.7.3.dev8/pfx/userjobs/views/user_job_attachment_view.py +17 -0
  61. django_pfx-1.7.3.dev8/pfx/userjobs/views/user_job_view.py +63 -0
  62. django_pfx-1.7.3.dev8/pfx/userjobs/views/user_websocket_consumer.py +65 -0
  63. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/requirements.txt +9 -1
  64. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/setup.cfg +1 -0
  65. django_pfx-1.7.3.dev8/tests/channel_group_send_calls.py +21 -0
  66. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/settings/common.py +29 -1
  67. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/__init__.py +7 -0
  68. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_auth_api.py +17 -14
  69. django_pfx-1.7.3.dev8/tests/tests/test_emails_email_api.py +86 -0
  70. django_pfx-1.7.3.dev8/tests/tests/test_emails_email_model.py +409 -0
  71. django_pfx-1.7.3.dev8/tests/tests/test_emails_q_mailjet_email_backend.py +175 -0
  72. django_pfx-1.7.3.dev8/tests/tests/test_emails_send_email_message.py +70 -0
  73. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_profiling_middleware.py +0 -1
  74. django_pfx-1.7.3.dev8/tests/tests/test_user_job_api.py +574 -0
  75. django_pfx-1.7.3.dev8/tests/tests/test_user_job_messages.py +128 -0
  76. django_pfx-1.7.3.dev8/tests/tests/test_user_job_model.py +302 -0
  77. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/urls.py +3 -1
  78. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/settings/common.py +26 -0
  79. django_pfx-1.7.3.dev8/tests_custom_user/migrations/__init__.py +0 -0
  80. django_pfx-1.7.3.dev8/tests_custom_user/settings/__init__.py +0 -0
  81. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/settings/common.py +26 -0
  82. django_pfx-1.7.3.dev4/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  83. django_pfx-1.7.3.dev4/pfx/settings/dev.py +0 -8
  84. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/.gitignore +0 -0
  85. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/.gitlab-ci.yml +0 -0
  86. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/LICENSE +0 -0
  87. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/MANIFEST.in +0 -0
  88. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/README.md +0 -0
  89. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/django_pfx.egg-info/dependency_links.txt +0 -0
  90. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/django_pfx.egg-info/top_level.txt +0 -0
  91. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/Makefile +0 -0
  92. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/index.rst +0 -0
  93. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/api.views.rst +0 -0
  94. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/authentication.md +0 -0
  95. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/decorator.md +0 -0
  96. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/generate_openapi.md +0 -0
  97. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/getting_started.md +0 -0
  98. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/internationalisation.md +0 -0
  99. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/model.md +0 -0
  100. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/pfx_views.md +0 -0
  101. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/profiling.md +0 -0
  102. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/settings.md +0 -0
  103. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/doc/source/testing.md +0 -0
  104. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/img/pfx.png +0 -0
  105. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/img/pfx.svg +0 -0
  106. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/manage.py +0 -0
  107. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/__init__.py +0 -0
  108. {django_pfx-1.7.3.dev4/pfx/pfxcore/management → django_pfx-1.7.3.dev8/pfx/emails/migrations}/__init__.py +0 -0
  109. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/apidoc/__init__.py +0 -0
  110. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/apidoc/parameters.py +0 -0
  111. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/apidoc/schema.py +0 -0
  112. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/apidoc/tags.py +0 -0
  113. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/decorator/__init__.py +0 -0
  114. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/decorator/rest.py +0 -0
  115. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/exceptions.py +0 -0
  116. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/fields/__init__.py +0 -0
  117. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/fields/decimal_field.py +0 -0
  118. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/fields/minutes_duration_field.py +0 -0
  119. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/fields/rich_text_field.py +0 -0
  120. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/http/__init__.py +0 -0
  121. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/http/json_response.py +0 -0
  122. {django_pfx-1.7.3.dev4/pfx/pfxcore/management/commands → django_pfx-1.7.3.dev8/pfx/pfxcore/management}/__init__.py +0 -0
  123. {django_pfx-1.7.3.dev4/pfx/pfxcore/serializers → django_pfx-1.7.3.dev8/pfx/pfxcore/management/commands}/__init__.py +0 -0
  124. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
  125. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/management/commands/profile.py +0 -0
  126. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/middleware/__init__.py +0 -0
  127. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/middleware/authentication.py +0 -0
  128. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/middleware/locale.py +0 -0
  129. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/middleware/profiling.py +0 -0
  130. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/migrations/0001_initial.py +0 -0
  131. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/migrations/0002_pfxpermissionsuser.py +0 -0
  132. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/migrations/0003_delete_pfxpermissionsuser.py +0 -0
  133. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/migrations/0004_alter_loginban_failed_counter_and_more.py +0 -0
  134. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/migrations/__init__.py +0 -0
  135. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/migrations/operations/__init__.py +0 -0
  136. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/migrations/operations/permissions.py +0 -0
  137. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
  138. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/cache_mixins.py +0 -0
  139. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/login_ban.py +0 -0
  140. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/mfa_user_mixin.py +0 -0
  141. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/not_null_fields.py +0 -0
  142. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/pfx_models.py +0 -0
  143. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/pfx_user.py +0 -0
  144. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  145. {django_pfx-1.7.3.dev4/pfx/pfxcore/sms/backends → django_pfx-1.7.3.dev8/pfx/pfxcore/serializers}/__init__.py +0 -0
  146. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/serializers/json.py +0 -0
  147. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/settings.py +0 -0
  148. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/sms/__init__.py +0 -0
  149. {django_pfx-1.7.3.dev4/pfx/settings → django_pfx-1.7.3.dev8/pfx/pfxcore/sms/backends}/__init__.py +0 -0
  150. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/sms/backends/base.py +0 -0
  151. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/sms/backends/console.py +0 -0
  152. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/storage/__init__.py +0 -0
  153. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/storage/exceptions.py +0 -0
  154. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/storage/local_storage.py +0 -0
  155. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/storage/s3_storage.py +0 -0
  156. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
  157. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  158. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  159. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/test.py +0 -0
  160. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/urls.py +0 -0
  161. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/__init__.py +0 -0
  162. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/authentication_views.py +0 -0
  163. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/fields.py +0 -0
  164. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/filters_views.py +0 -0
  165. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/locale_views.py +0 -0
  166. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/media_rest_view_mixin.py +0 -0
  167. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/ordered_rest_view_mixin.py +0 -0
  168. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  169. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  170. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/groups.py +0 -0
  171. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  172. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  173. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  174. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  175. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  176. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  177. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  178. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  179. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  180. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/subset.py +0 -0
  181. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  182. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  183. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  184. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  185. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  186. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pfx/pfxcore/views/rest_views.py +0 -0
  187. {django_pfx-1.7.3.dev4/tests → django_pfx-1.7.3.dev8/pfx/settings}/__init__.py +0 -0
  188. {django_pfx-1.7.3.dev4/tests → django_pfx-1.7.3.dev8/pfx/userjobs}/migrations/__init__.py +0 -0
  189. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/pyproject.toml +0 -0
  190. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/serve-doc +0 -0
  191. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/setup.py +0 -0
  192. {django_pfx-1.7.3.dev4/tests/settings → django_pfx-1.7.3.dev8/tests}/__init__.py +0 -0
  193. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/apps.py +0 -0
  194. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
  195. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/migrations/0001_initial.py +0 -0
  196. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/migrations/0002_alter_book_cover.py +0 -0
  197. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/migrations/0003_book_local_file.py +0 -0
  198. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/migrations/0004_mfausermixin_fields.py +0 -0
  199. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/migrations/0005_mfausermixin_fields_fix.py +0 -0
  200. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/migrations/0006_rename_otp_enabled_user_mfa_authenticator_enabled_and_more.py +0 -0
  201. {django_pfx-1.7.3.dev4/tests_base_user → django_pfx-1.7.3.dev8/tests/migrations}/__init__.py +0 -0
  202. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/models.py +0 -0
  203. {django_pfx-1.7.3.dev4/tests_base_user/migrations → django_pfx-1.7.3.dev8/tests/settings}/__init__.py +0 -0
  204. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/settings/ci.py +0 -0
  205. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/settings/dev.py +0 -0
  206. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/settings/dev_custom_example.py +0 -0
  207. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/settings/dev_default.py +0 -0
  208. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/basic_api_errors.py +0 -0
  209. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/basic_api_test.py +0 -0
  210. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_api_doc.py +0 -0
  211. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_api_doc_search.py +0 -0
  212. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_body_mixin.py +0 -0
  213. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_cache.py +0 -0
  214. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_client.py +0 -0
  215. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_fields_choices.py +0 -0
  216. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_fields_date.py +0 -0
  217. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_fields_decimal.py +0 -0
  218. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_fields_minutes_duration.py +0 -0
  219. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_fields_one2many.py +0 -0
  220. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_fields_rich_text.py +0 -0
  221. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_fields_time.py +0 -0
  222. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_filters.py +0 -0
  223. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_locale_api.py +0 -0
  224. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_ordered_rest_view_mixin.py +0 -0
  225. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_perm_tests.py +0 -0
  226. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_permissions.py +0 -0
  227. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_perms_api.py +0 -0
  228. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_post_migrate_groups_update.py +0 -0
  229. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_settings.py +0 -0
  230. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_shortcuts.py +0 -0
  231. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_timezone_middleware.py +0 -0
  232. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_tools.py +0 -0
  233. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_user_queryset.py +0 -0
  234. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_view_decorators.py +0 -0
  235. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/tests/test_view_fields.py +0 -0
  236. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests/views.py +0 -0
  237. {django_pfx-1.7.3.dev4/tests_base_user/settings → django_pfx-1.7.3.dev8/tests_base_user}/__init__.py +0 -0
  238. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/migrations/0001_initial.py +0 -0
  239. {django_pfx-1.7.3.dev4/tests_custom_user → django_pfx-1.7.3.dev8/tests_base_user/migrations}/__init__.py +0 -0
  240. {django_pfx-1.7.3.dev4/tests_custom_user/migrations → django_pfx-1.7.3.dev8/tests_base_user/settings}/__init__.py +0 -0
  241. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/settings/ci.py +0 -0
  242. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/settings/dev.py +0 -0
  243. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/settings/dev_custom_example.py +0 -0
  244. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/settings/dev_default.py +0 -0
  245. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/tests/__init__.py +0 -0
  246. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/tests/test_api.py +0 -0
  247. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/tests/test_auth_api.py +0 -0
  248. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/urls.py +0 -0
  249. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_base_user/views.py +0 -0
  250. {django_pfx-1.7.3.dev4/tests_custom_user/settings → django_pfx-1.7.3.dev8/tests_custom_user}/__init__.py +0 -0
  251. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/migrations/0001_initial.py +0 -0
  252. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/models.py +0 -0
  253. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/settings/ci.py +0 -0
  254. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/settings/dev.py +0 -0
  255. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/settings/dev_custom_example.py +0 -0
  256. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/settings/dev_default.py +0 -0
  257. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/tests/__init__.py +0 -0
  258. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/tests/test_api.py +0 -0
  259. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/tests/test_auth_api.py +0 -0
  260. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/urls.py +0 -0
  261. {django_pfx-1.7.3.dev4 → django_pfx-1.7.3.dev8}/tests_custom_user/views.py +0 -0
@@ -1,11 +1,11 @@
1
1
  repos:
2
- - repo: https://github.com/pre-commit/pre-commit-hooks
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
3
  rev: v4.3.0
4
4
  hooks:
5
- - id: check-yaml
6
- - id: end-of-file-fixer
7
- - id: trailing-whitespace
8
- - repo: local
5
+ - id: check-yaml
6
+ - id: end-of-file-fixer
7
+ - id: trailing-whitespace
8
+ - repo: local
9
9
  hooks:
10
10
  - id: flake8
11
11
  name: flake8
@@ -13,17 +13,17 @@ repos:
13
13
  language: system
14
14
  types: [python]
15
15
  args: [--config=./setup.cfg]
16
- - repo: local
16
+ - repo: local
17
17
  hooks:
18
18
  - id: isort
19
19
  name: isort
20
20
  entry: isort
21
21
  language: system
22
22
  types: [python]
23
- - repo: local
23
+ - repo: local
24
24
  hooks:
25
25
  - id: make-messages
26
26
  name: make messages
27
27
  entry: ./make_messages
28
28
  language: system
29
- types: [python]
29
+ pass_filenames: false
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-pfx
3
- Version: 1.7.3.dev4
3
+ Version: 1.7.3.dev8
4
4
  Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -37,6 +37,9 @@ Requires-Dist: dill
37
37
  Requires-Dist: nh3
38
38
  Provides-Extra: otp
39
39
  Requires-Dist: pyotp; extra == "otp"
40
+ Provides-Extra: heic-converter
41
+ Requires-Dist: python-magic; extra == "heic-converter"
42
+ Requires-Dist: pillow-heif; extra == "heic-converter"
40
43
  Dynamic: license-file
41
44
 
42
45
  # Django PFX
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-pfx
3
- Version: 1.7.3.dev4
3
+ Version: 1.7.3.dev8
4
4
  Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -37,6 +37,9 @@ Requires-Dist: dill
37
37
  Requires-Dist: nh3
38
38
  Provides-Extra: otp
39
39
  Requires-Dist: pyotp; extra == "otp"
40
+ Provides-Extra: heic-converter
41
+ Requires-Dist: python-magic; extra == "heic-converter"
42
+ Requires-Dist: pillow-heif; extra == "heic-converter"
40
43
  Dynamic: license-file
41
44
 
42
45
  # Django PFX
@@ -33,6 +33,30 @@ doc/source/testing.md
33
33
  img/pfx.png
34
34
  img/pfx.svg
35
35
  pfx/__init__.py
36
+ pfx/emails/__init__.py
37
+ pfx/emails/apps.py
38
+ pfx/emails/exceptions.py
39
+ pfx/emails/shortcuts.py
40
+ pfx/emails/tasks.py
41
+ pfx/emails/urls.py
42
+ pfx/emails/email_backend/__init__.py
43
+ pfx/emails/email_backend/q_mailjet_email_backend.py
44
+ pfx/emails/mailjet/__init__.py
45
+ pfx/emails/mailjet/mailjet.py
46
+ pfx/emails/mailjet/message_result.py
47
+ pfx/emails/migrations/0001_initial.py
48
+ pfx/emails/migrations/0002_alter_email_headers.py
49
+ pfx/emails/migrations/0003_alter_email_options.py
50
+ pfx/emails/migrations/__init__.py
51
+ pfx/emails/models/__init__.py
52
+ pfx/emails/models/email.py
53
+ pfx/emails/providers/__init__.py
54
+ pfx/emails/providers/email_django_q_executor.py
55
+ pfx/emails/templates/emails/base_template.html
56
+ pfx/emails/templates/emails/base_template.txt
57
+ pfx/emails/templates/emails/base_template_subject.txt
58
+ pfx/emails/views/__init__.py
59
+ pfx/emails/views/email_rest_view.py
36
60
  pfx/pfxcore/__init__.py
37
61
  pfx/pfxcore/apps.py
38
62
  pfx/pfxcore/default_settings.py
@@ -73,6 +97,7 @@ pfx/pfxcore/migrations/operations/__init__.py
73
97
  pfx/pfxcore/migrations/operations/permissions.py
74
98
  pfx/pfxcore/models/__init__.py
75
99
  pfx/pfxcore/models/abstract_pfx_base_user.py
100
+ pfx/pfxcore/models/attachment_mixin.py
76
101
  pfx/pfxcore/models/cache_mixins.py
77
102
  pfx/pfxcore/models/login_ban.py
78
103
  pfx/pfxcore/models/mfa_user_mixin.py
@@ -125,8 +150,28 @@ pfx/pfxcore/views/parameters/subset_page_size.py
125
150
  pfx/pfxcore/views/parameters/subset_page_subset.py
126
151
  pfx/settings/__init__.py
127
152
  pfx/settings/dev.py
153
+ pfx/userjobs/__init__.py
154
+ pfx/userjobs/apps.py
155
+ pfx/userjobs/tasks.py
156
+ pfx/userjobs/urls.py
157
+ pfx/userjobs/locale/fr/LC_MESSAGES/django.mo
158
+ pfx/userjobs/locale/fr/LC_MESSAGES/django.po
159
+ pfx/userjobs/migrations/0001_initial.py
160
+ pfx/userjobs/migrations/0002_alter_userjob_options_alter_userjob_auto_queued_and_more.py
161
+ pfx/userjobs/migrations/__init__.py
162
+ pfx/userjobs/models/__init__.py
163
+ pfx/userjobs/models/user_job.py
164
+ pfx/userjobs/models/user_job_attachment.py
165
+ pfx/userjobs/providers/__init__.py
166
+ pfx/userjobs/providers/user_job_django_q_executor.py
167
+ pfx/userjobs/providers/user_job_websocket_channel_provider.py
168
+ pfx/userjobs/views/__init__.py
169
+ pfx/userjobs/views/user_job_attachment_view.py
170
+ pfx/userjobs/views/user_job_view.py
171
+ pfx/userjobs/views/user_websocket_consumer.py
128
172
  tests/__init__.py
129
173
  tests/apps.py
174
+ tests/channel_group_send_calls.py
130
175
  tests/models.py
131
176
  tests/urls.py
132
177
  tests/views.py
@@ -153,6 +198,10 @@ tests/tests/test_auth_api.py
153
198
  tests/tests/test_body_mixin.py
154
199
  tests/tests/test_cache.py
155
200
  tests/tests/test_client.py
201
+ tests/tests/test_emails_email_api.py
202
+ tests/tests/test_emails_email_model.py
203
+ tests/tests/test_emails_q_mailjet_email_backend.py
204
+ tests/tests/test_emails_send_email_message.py
156
205
  tests/tests/test_fields_choices.py
157
206
  tests/tests/test_fields_date.py
158
207
  tests/tests/test_fields_decimal.py
@@ -172,6 +221,9 @@ tests/tests/test_settings.py
172
221
  tests/tests/test_shortcuts.py
173
222
  tests/tests/test_timezone_middleware.py
174
223
  tests/tests/test_tools.py
224
+ tests/tests/test_user_job_api.py
225
+ tests/tests/test_user_job_messages.py
226
+ tests/tests/test_user_job_model.py
175
227
  tests/tests/test_user_queryset.py
176
228
  tests/tests/test_view_decorators.py
177
229
  tests/tests/test_view_fields.py
@@ -9,5 +9,9 @@ pytz
9
9
  dill
10
10
  nh3
11
11
 
12
+ [heic-converter]
13
+ python-magic
14
+ pillow-heif
15
+
12
16
  [otp]
13
17
  pyotp
@@ -25,7 +25,9 @@ settings.configure(
25
25
  'django.contrib.auth',
26
26
  'django.contrib.contenttypes',
27
27
  'django.contrib.postgres',
28
- 'pfx.pfxcore'])
28
+ 'pfx.pfxcore',
29
+ 'pfx.userjobs'],
30
+ STORAGE_DEFAULT='pfx.pfxcore.storage.LocalStorage')
29
31
  django.setup()
30
32
 
31
33
 
@@ -1,3 +1,4 @@
1
1
  #!/usr/bin/env bash
2
2
  (cd pfx/pfxcore && django-admin makemessages -a)
3
+ (cd pfx/userjobs && django-admin makemessages -a)
3
4
  (cd tests && django-admin makemessages -a)
@@ -0,0 +1 @@
1
+ from .apps import EmailsConfig
@@ -0,0 +1,14 @@
1
+ from django.apps import AppConfig
2
+ from django.db.models.signals import post_migrate
3
+
4
+
5
+ class EmailsConfig(AppConfig):
6
+ name = 'pfx.emails'
7
+ default = True
8
+
9
+ def ready(self):
10
+ from pfx.emails.models.email import get_executor
11
+ executor = get_executor()
12
+ executor.validate_setup()
13
+ post_migrate.connect(executor.register_periodic_tasks, sender=self)
14
+ super().ready()
@@ -0,0 +1 @@
1
+ from .q_mailjet_email_backend import QMailjetEmailBackend
@@ -0,0 +1,96 @@
1
+ import base64
2
+ import email.utils
3
+ import logging
4
+ from email.mime.base import MIMEBase
5
+
6
+ from django.core.mail import EmailMultiAlternatives
7
+ from django.core.mail.backends.base import BaseEmailBackend
8
+
9
+ from pfx.emails.models import get_email_model
10
+ from pfx.emails.shortcuts import default_mail_from, default_reply_to
11
+
12
+
13
+ def getaddresses(fieldvalues):
14
+ return email.utils.getaddresses(fieldvalues, strict=False)
15
+
16
+
17
+ class QMailjetEmailBackend(BaseEmailBackend):
18
+
19
+ def send_messages(self, email_messages):
20
+ cnt = 0
21
+ for message in email_messages:
22
+ self.create_mail(message)
23
+ cnt += 1
24
+ return cnt
25
+
26
+ def create_extra_values(self, message):
27
+ return {}
28
+
29
+ def create_mail(self, message):
30
+ if not message.from_email:
31
+ mail_from = default_mail_from()
32
+ else:
33
+ mail_from = self.mail_dict(*getaddresses(
34
+ [message.from_email])[0])
35
+
36
+ parts = {}
37
+ if isinstance(message, EmailMultiAlternatives):
38
+ html_content = None
39
+ for content, mt in message.alternatives:
40
+ if mt == 'text/html':
41
+ html_content = content
42
+ parts['text_part'] = message.body
43
+ parts['html_part'] = html_content
44
+ elif message.content_subtype == "html":
45
+ parts['html_part'] = message.body
46
+ else:
47
+ parts['text_part'] = message.body
48
+
49
+ attachments = []
50
+ for msg_att in message.attachments:
51
+ if isinstance(msg_att, MIMEBase):
52
+ filename = msg_att.get_filename()
53
+ content_type = msg_att.get_content_type()
54
+ content = msg_att.get_payload(decode=True)
55
+ else:
56
+ filename, content, content_type = msg_att
57
+ if isinstance(content, str):
58
+ content = content.encode('utf-8')
59
+ attachments.append({
60
+ 'ContentType': content_type,
61
+ 'Filename': filename,
62
+ 'Base64Content': base64.b64encode(content).decode('utf-8')})
63
+
64
+ headers = message.extra_headers
65
+ reply_to = default_reply_to()
66
+ if message.reply_to:
67
+ headers["Reply-To"] = ', '.join(message.reply_to)
68
+ elif not headers.get("Reply-To") and reply_to:
69
+ headers["Reply-To"] = reply_to
70
+
71
+ email = get_email_model()(
72
+ mail_from=mail_from,
73
+ mail_to=[
74
+ self.mail_dict(*e) for e in getaddresses(message.to)],
75
+ mail_cc=[
76
+ self.mail_dict(*e) for e in getaddresses(message.cc)],
77
+ mail_bcc=[
78
+ self.mail_dict(*e) for e in getaddresses(message.bcc)],
79
+ subject=message.subject,
80
+ headers=headers,
81
+ attachments=attachments,
82
+ send_mode=getattr(message, 'send_mode', 'auto_async'),
83
+ **parts,
84
+ **self.create_extra_values(message))
85
+ email.full_clean()
86
+ email.save()
87
+
88
+ @staticmethod
89
+ def mail_dict(name, mail):
90
+ res = {'Email': mail}
91
+ if name:
92
+ res['Name'] = name
93
+ return res
94
+
95
+
96
+ logger = logging.getLogger(__name__)
@@ -0,0 +1,2 @@
1
+ class HasRunningTaskException(Exception):
2
+ pass
@@ -0,0 +1,2 @@
1
+ from .mailjet import *
2
+ from .message_result import *
@@ -0,0 +1,18 @@
1
+ from django.conf import settings
2
+
3
+
4
+ def Mailjet(version='v3'):
5
+ try:
6
+ from mailjet_rest.client import Client
7
+ except Exception as e:
8
+ raise RuntimeError(
9
+ "mailjet_rest library missing.") from e
10
+
11
+ key_public = getattr(settings, 'PFX_MJ_APIKEY_PUBLIC', None)
12
+ key_private = getattr(settings, 'PFX_MJ_APIKEY_PRIVATE', None)
13
+ try:
14
+ return Client(auth=(key_public, key_private), version=version)
15
+ except Exception as e:
16
+ raise RuntimeError(
17
+ "Invalid PFX_MJ_APIKEY_PUBLIC and/or "
18
+ "PFX_MJ_APIKEY_PRIVATE settings") from e
@@ -0,0 +1,32 @@
1
+ import logging
2
+
3
+ logger = logging.getLogger(__name__)
4
+
5
+
6
+ class Event:
7
+ def __init__(self, json):
8
+ self.json = json
9
+
10
+ @property
11
+ def status(self):
12
+ return self.json.get("Status", 'unknown')
13
+
14
+ @property
15
+ def is_permanent(self):
16
+ return self.status == 'sent' or self.json.get("StatePermanent")
17
+
18
+
19
+ class Message:
20
+ def __init__(self, json):
21
+ self.json = json
22
+
23
+ @property
24
+ def event(self):
25
+ events = self.json.get('Data', [])
26
+ return Event(events and "Status" in events[0] and events[0] or {})
27
+
28
+
29
+ class MessageResult(Message):
30
+ def __init__(self, result):
31
+ super().__init__(result.json())
32
+ self.status_code = result.status_code
@@ -0,0 +1,47 @@
1
+ # Generated by Django 4.2.30 on 2026-05-27 09:11
2
+ # flake8: noqa
3
+
4
+ from django.db import migrations, models
5
+
6
+ import pfx.emails.shortcuts
7
+ import pfx.pfxcore.models.not_null_fields
8
+
9
+
10
+ class Migration(migrations.Migration):
11
+
12
+ initial = True
13
+
14
+ dependencies = [
15
+ ]
16
+
17
+ operations = [
18
+ migrations.CreateModel(
19
+ name='Email',
20
+ fields=[
21
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22
+ ('send_date', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Send date')),
23
+ ('mail_from', models.JSONField(default=pfx.emails.shortcuts.default_mail_from, verbose_name='Mail From')),
24
+ ('mail_to', models.JSONField(default=list, verbose_name='Mail To')),
25
+ ('mail_cc', models.JSONField(blank=True, default=list, verbose_name='Mail Cc')),
26
+ ('mail_bcc', models.JSONField(blank=True, default=list, verbose_name='Mail Bcc')),
27
+ ('subject', models.CharField(max_length=255, verbose_name='Subject')),
28
+ ('text_part', pfx.pfxcore.models.not_null_fields.NotNullTextField(blank=True, verbose_name='Text Part')),
29
+ ('html_part', pfx.pfxcore.models.not_null_fields.NotNullTextField(blank=True, verbose_name='HTML Part')),
30
+ ('headers', models.JSONField(default=dict, verbose_name='Headers')),
31
+ ('attachments', models.JSONField(blank=True, default=list, verbose_name='Attachments')),
32
+ ('status', models.CharField(choices=[('to_send', 'To send'), ('sending', 'Sending'), ('sent', 'Sent'), ('delivered', 'Delivered'), ('delivery_error', 'Delivery Error'), ('error', 'Error'), ('error_retry', 'Error Retry'), ('blocked', 'Blocked')], db_index=True, default='to_send', max_length=32, verbose_name='Status')),
33
+ ('status_code', models.IntegerField(blank=True, null=True, verbose_name='HTTP Status Code')),
34
+ ('errors', models.JSONField(blank=True, null=True, verbose_name='Errors')),
35
+ ('send_mode', models.CharField(choices=[('manual', 'Manual'), ('auto', 'Auto'), ('auto_async', 'Auto Async')], db_index=True, default='auto_async', max_length=32, verbose_name='Send Mode')),
36
+ ('delete_delivered', models.BooleanField(default=True, verbose_name='Delete Delivered')),
37
+ ('send_task_id', models.CharField(blank=True, max_length=255, null=True, unique=True, verbose_name='Send Task Id')),
38
+ ('retry_count', models.IntegerField(default=0, verbose_name='Retry count')),
39
+ ],
40
+ options={
41
+ 'verbose_name': 'Email',
42
+ 'verbose_name_plural': 'Emails',
43
+ 'db_table': 'emails_email',
44
+ 'ordering': ['send_date'],
45
+ },
46
+ ),
47
+ ]
@@ -0,0 +1,19 @@
1
+ # Generated by Django 4.2.30 on 2026-06-01 00:26
2
+ # flake8: noqa
3
+
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('emails', '0001_initial'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name='email',
16
+ name='headers',
17
+ field=models.JSONField(blank=True, default=dict, verbose_name='Headers'),
18
+ ),
19
+ ]
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.2.30 on 2026-06-01 00:58
2
+ # flake8: noqa
3
+
4
+ from django.db import migrations
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('emails', '0002_alter_email_headers'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterModelOptions(
15
+ name='email',
16
+ options={},
17
+ ),
18
+ ]
@@ -0,0 +1 @@
1
+ from .email import AbstractEmail, Email, get_email_model