modoboa 2.4.10__py3-none-any.whl → 2.5.0__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.
Files changed (331) hide show
  1. modoboa/admin/api/v1/serializers.py +1 -0
  2. modoboa/admin/api/v2/serializers.py +15 -1
  3. modoboa/admin/api/v2/tests.py +11 -1
  4. modoboa/admin/lib.py +1 -1
  5. modoboa/admin/models/mailbox.py +15 -13
  6. modoboa/admin/models/mxrecord.py +4 -0
  7. modoboa/admin/tests/test_import_.py +11 -11
  8. modoboa/amavis/__init__.py +3 -0
  9. modoboa/amavis/app_settings.py +276 -0
  10. modoboa/amavis/apps.py +18 -0
  11. modoboa/amavis/checks/__init__.py +2 -0
  12. modoboa/amavis/checks/settings_checks.py +59 -0
  13. modoboa/amavis/dbrouter.py +35 -0
  14. modoboa/amavis/factories.py +164 -0
  15. modoboa/amavis/handlers.py +146 -0
  16. modoboa/amavis/lib.py +381 -0
  17. modoboa/amavis/management/__init__.py +0 -0
  18. modoboa/amavis/management/commands/__init__.py +0 -0
  19. modoboa/amavis/management/commands/amnotify.py +99 -0
  20. modoboa/amavis/management/commands/qcleanup.py +84 -0
  21. modoboa/amavis/migrations/0001_initial.py +340 -0
  22. modoboa/amavis/migrations/__init__.py +0 -0
  23. modoboa/amavis/models.py +226 -0
  24. modoboa/amavis/serializers.py +139 -0
  25. modoboa/amavis/sql_connector.py +240 -0
  26. modoboa/amavis/sql_email.py +66 -0
  27. modoboa/amavis/tasks.py +33 -0
  28. modoboa/amavis/templates/amavis/notifications/pending_requests.html +16 -0
  29. modoboa/amavis/tests/__init__.py +0 -0
  30. modoboa/amavis/tests/sa-learn +3 -0
  31. modoboa/amavis/tests/sample_messages/quarantined-input.txt +80 -0
  32. modoboa/amavis/tests/sample_messages/quarantined-output-plain_nolinks.txt +17 -0
  33. modoboa/amavis/tests/spamc +3 -0
  34. modoboa/amavis/tests/test_checks.py +25 -0
  35. modoboa/amavis/tests/test_handlers.py +214 -0
  36. modoboa/amavis/tests/test_lib.py +90 -0
  37. modoboa/amavis/tests/test_management_commands.py +45 -0
  38. modoboa/amavis/tests/test_sql_email.py +67 -0
  39. modoboa/amavis/tests/test_utils.py +19 -0
  40. modoboa/amavis/tests/test_viewsets.py +319 -0
  41. modoboa/amavis/urls.py +11 -0
  42. modoboa/amavis/utils.py +105 -0
  43. modoboa/amavis/viewsets.py +265 -0
  44. modoboa/core/api/v1/serializers.py +7 -5
  45. modoboa/core/api/v2/serializers.py +13 -2
  46. modoboa/core/api/v2/tests.py +34 -4
  47. modoboa/core/api/v2/urls.py +10 -5
  48. modoboa/core/api/v2/views.py +23 -2
  49. modoboa/core/api/v2/viewsets.py +24 -3
  50. modoboa/core/app_settings.py +11 -0
  51. modoboa/core/fido2_auth.py +1 -2
  52. modoboa/core/handlers.py +6 -2
  53. modoboa/core/management/commands/add_allowed_hosts.py +33 -0
  54. modoboa/core/management/commands/cleanlogs.py +9 -0
  55. modoboa/core/management/commands/load_initial_data.py +10 -0
  56. modoboa/core/migrations/0025_rename_user_email_is_active_core_user_email_c0c03f_idx.py +23 -5
  57. modoboa/core/tests/test_core.py +29 -0
  58. modoboa/core/utils.py +6 -0
  59. modoboa/dnstools/api/v2/serializers.py +9 -11
  60. modoboa/frontend_dist/assets/AccountAliasForm-BuSy_1n9.js +1 -0
  61. modoboa/frontend_dist/assets/AccountEditView-qdJmLM_e.js +1 -0
  62. modoboa/frontend_dist/assets/AccountLayout-DrN7vHsX.js +1 -0
  63. modoboa/frontend_dist/assets/AccountPasswordSubForm-DZGt_Xgq.js +1 -0
  64. modoboa/frontend_dist/assets/AccountView-CO65y0vZ.js +1 -0
  65. modoboa/frontend_dist/assets/AddressBook-BZNUlhek.js +1 -0
  66. modoboa/frontend_dist/assets/AdminLayout-CTNhuwTw.js +1 -0
  67. modoboa/frontend_dist/assets/AlarmsView-9yKGbmkC.css +1 -0
  68. modoboa/frontend_dist/assets/AlarmsView-DN_JIw9g.js +1 -0
  69. modoboa/frontend_dist/assets/AliasEditView-DjpPUTp9.js +1 -0
  70. modoboa/frontend_dist/assets/{AliasRecipientForm-DVZXWaUX.js → AliasRecipientForm-B1Y8wFdP.js} +1 -1
  71. modoboa/frontend_dist/assets/AliasView-GOJ5lyQH.js +1 -0
  72. modoboa/frontend_dist/assets/AuditTrailView-fbXmq70e.js +1 -0
  73. modoboa/frontend_dist/assets/CalendarView-LlQQNEPL.js +1 -0
  74. modoboa/frontend_dist/assets/{ChoiceField-7eU7c_rI.js → ChoiceField-B3ReQHVe.js} +1 -1
  75. modoboa/frontend_dist/assets/ComposeEmailForm-Bs1fZXAL.js +1 -0
  76. modoboa/frontend_dist/assets/ComposeEmailView-s3LMl3pO.js +1 -0
  77. modoboa/frontend_dist/assets/ConfirmDialog-DY_kUHLG.js +1 -0
  78. modoboa/frontend_dist/assets/{ConnectedLayout-BaJZ3BeR.css → ConnectedLayout-Bxh21hcH.css} +1 -1
  79. modoboa/frontend_dist/assets/ConnectedLayout-UWjiYBNw.js +1 -0
  80. modoboa/frontend_dist/assets/CreationForm-ORg3fazt.js +1 -0
  81. modoboa/frontend_dist/assets/DashboardView-Dplk9itS.js +1 -0
  82. modoboa/frontend_dist/assets/{DashboardView-BLlMi6Qb.css → DashboardView-gwwVAPvt.css} +1 -1
  83. modoboa/frontend_dist/assets/DomainAdminList-DVn9x0rB.js +1 -0
  84. modoboa/frontend_dist/assets/DomainEditView-nAoL64D_.js +1 -0
  85. modoboa/frontend_dist/assets/{DomainTransportForm-DPnPGBOp.js → DomainTransportForm-CA-DNUxX.js} +1 -1
  86. modoboa/frontend_dist/assets/{DomainView-BDKoBFYr.css → DomainView-CCLYXPHx.css} +1 -1
  87. modoboa/frontend_dist/assets/DomainView-CdXPpwJG.js +5 -0
  88. modoboa/frontend_dist/assets/DomainsView-B_59gowf.js +1 -0
  89. modoboa/frontend_dist/assets/DomainsView-DZ-ss9bI.css +1 -0
  90. modoboa/frontend_dist/assets/EmailField-CwcwI5xW.js +1 -0
  91. modoboa/frontend_dist/assets/EmailView-BshxcfAK.js +1 -0
  92. modoboa/frontend_dist/assets/EmptyLayout-DFfhnhLi.js +1 -0
  93. modoboa/frontend_dist/assets/FiltersView-Cf20MSTK.js +1 -0
  94. modoboa/frontend_dist/assets/ForwardEmailView-CZG062os.js +1 -0
  95. modoboa/frontend_dist/assets/{HtmlEditor-uM4AtIGi.js → HtmlEditor-Bh4c689R.js} +1 -1
  96. modoboa/frontend_dist/assets/IdentitiesView-BXAuU1YX.js +1 -0
  97. modoboa/frontend_dist/assets/{IdentitiesView-jmuItyMZ.css → IdentitiesView-DPrrRMS5.css} +1 -1
  98. modoboa/frontend_dist/assets/InformationView-C9vvvQhJ.css +1 -0
  99. modoboa/frontend_dist/assets/InformationView-Cn5FZW7H.js +1 -0
  100. modoboa/frontend_dist/assets/{LoadingData-CVD2Aen8.js → LoadingData-CdVvm4FI.js} +1 -1
  101. modoboa/frontend_dist/assets/{LoginCallbackView-sWzBke1g.js → LoginCallbackView-B9hAH4MI.js} +1 -1
  102. modoboa/frontend_dist/assets/{LoginView-wmN73W0f.js → LoginView-tHIR4Adc.js} +1 -1
  103. modoboa/frontend_dist/assets/MailboxView-Bugu2vhg.js +1 -0
  104. modoboa/frontend_dist/assets/MenuItems-PXjiG-fs.js +1 -0
  105. modoboa/frontend_dist/assets/MessageView-Cy4STShm.js +1 -0
  106. modoboa/frontend_dist/assets/MessagesView-DdkuEgfX.js +1 -0
  107. modoboa/frontend_dist/assets/MigrationsView-CidSEjCF.js +1 -0
  108. modoboa/frontend_dist/assets/{ParametersForm-BCeQljir.js → ParametersForm-CAv4SH-E.js} +1 -1
  109. modoboa/frontend_dist/assets/ParametersView-CX7Ffemw.js +1 -0
  110. modoboa/frontend_dist/assets/ParametersView-CrbNcmV3.js +1 -0
  111. modoboa/frontend_dist/assets/ProviderEditView-CrltAQXl.js +1 -0
  112. modoboa/frontend_dist/assets/ProviderGeneralForm-BYAzVnXM.js +1 -0
  113. modoboa/frontend_dist/assets/ProvidersView-osjIY4Ex.js +1 -0
  114. modoboa/frontend_dist/assets/QuarantineLayout-B8EcU9vS.js +1 -0
  115. modoboa/frontend_dist/assets/QuarantineView-D4gOE4EQ.css +1 -0
  116. modoboa/frontend_dist/assets/QuarantineView-D8Qg0MXA.js +1 -0
  117. modoboa/frontend_dist/assets/ReplyEmailView-BABPqWhd.js +1 -0
  118. modoboa/frontend_dist/assets/ResourcesForm-OaqdRYVs.js +1 -0
  119. modoboa/frontend_dist/assets/SelfServiceLayout-d277YTGR.js +1 -0
  120. modoboa/frontend_dist/assets/SettingsView-9iNcDhkI.js +6 -0
  121. modoboa/frontend_dist/assets/StatisticsView-cHsPyGkL.js +1 -0
  122. modoboa/frontend_dist/assets/TimeSerieChart--V83dcJ9.js +1 -0
  123. modoboa/frontend_dist/assets/UserLayout-B3sBiTcZ.js +1 -0
  124. modoboa/frontend_dist/assets/VAlert-BuaaYN2h.js +1 -0
  125. modoboa/frontend_dist/assets/VApp-CKP-6zGP.js +1 -0
  126. modoboa/frontend_dist/assets/VAutocomplete-Dwv6_Rzq.js +1 -0
  127. modoboa/frontend_dist/assets/VAvatar-Cmga0vj6.js +1 -0
  128. modoboa/frontend_dist/assets/VBadge-BQrRJ9S0.css +1 -0
  129. modoboa/frontend_dist/assets/VBadge-CixeK87a.js +1 -0
  130. modoboa/frontend_dist/assets/VCard-CxH9DWoK.js +1 -0
  131. modoboa/frontend_dist/assets/VCheckbox-62GOpvvP.js +1 -0
  132. modoboa/frontend_dist/assets/{VCheckboxBtn-j7di4leN.js → VCheckboxBtn-DMoNtKT8.js} +1 -1
  133. modoboa/frontend_dist/assets/VChip-D_styETR.js +1 -0
  134. modoboa/frontend_dist/assets/VColorPicker-BHscBGQV.js +1 -0
  135. modoboa/frontend_dist/assets/VContainer-B46caNs1.js +1 -0
  136. modoboa/frontend_dist/assets/VDataTable-Bh8NbVSx.js +1 -0
  137. modoboa/frontend_dist/assets/VDataTableServer-BDR5hOmo.js +1 -0
  138. modoboa/frontend_dist/assets/VDataTableVirtual-BOQlNtIG.js +1 -0
  139. modoboa/frontend_dist/assets/{VDialog-CZqM2Ofu.js → VDialog-BcTg7w6P.js} +1 -1
  140. modoboa/frontend_dist/assets/VExpansionPanels-BmH5Jl2Z.js +1 -0
  141. modoboa/frontend_dist/assets/VFileInput-BC4yAygd.js +1 -0
  142. modoboa/frontend_dist/assets/VForm-D5iPGkde.js +1 -0
  143. modoboa/frontend_dist/assets/VInput-CcxkaOXT.css +1 -0
  144. modoboa/frontend_dist/assets/VInput-CoDJzvaW.js +1 -0
  145. modoboa/frontend_dist/assets/VMenu-gUG70-zD.js +1 -0
  146. modoboa/frontend_dist/assets/VPicker-BXuKT3zB.js +1 -0
  147. modoboa/frontend_dist/assets/VProgressCircular-BtOPiGCg.js +1 -0
  148. modoboa/frontend_dist/assets/VRadioGroup-DIFZKSn-.js +1 -0
  149. modoboa/frontend_dist/assets/{VRow-C_Ydf6yr.js → VRow-ozg66L7j.js} +1 -1
  150. modoboa/frontend_dist/assets/VSelect-C3RjAa45.js +1 -0
  151. modoboa/frontend_dist/assets/VSelectionControl-zyz-fJvC.js +1 -0
  152. modoboa/frontend_dist/assets/VSheet-BNx2X4Mk.js +1 -0
  153. modoboa/frontend_dist/assets/VSpacer-DinPiXs9.js +1 -0
  154. modoboa/frontend_dist/assets/VSwitch-DwxdeAEq.js +1 -0
  155. modoboa/frontend_dist/assets/VTable-DaLxa4FO.js +1 -0
  156. modoboa/frontend_dist/assets/VTabs-BP0Hgsgm.js +1 -0
  157. modoboa/frontend_dist/assets/VTextField-BzBVKKob.css +1 -0
  158. modoboa/frontend_dist/assets/VTextField-XoGTj1KG.js +1 -0
  159. modoboa/frontend_dist/assets/VTextarea-wBlRMIv_.js +1 -0
  160. modoboa/frontend_dist/assets/VToolbar-CFZfqeOr.js +1 -0
  161. modoboa/frontend_dist/assets/VWindowItem-BB7ETW3b.js +1 -0
  162. modoboa/frontend_dist/assets/WebmailLayout-_Hk1XhVq.js +1 -0
  163. modoboa/frontend_dist/assets/accounts-DUzbx6k8.js +1 -0
  164. modoboa/frontend_dist/assets/admin-DewTk2H8.js +1 -0
  165. modoboa/frontend_dist/assets/{aliases-c3n-dCV_.js → aliases-4sXmjwXp.js} +1 -1
  166. modoboa/frontend_dist/assets/amavis-CC0li7_T.js +1 -0
  167. modoboa/frontend_dist/assets/amavis-DK8SHE6o.js +1 -0
  168. modoboa/frontend_dist/assets/{contacts-Bqckz8sr.js → contacts-BjghrPqZ.js} +1 -1
  169. modoboa/frontend_dist/assets/{domains-nBMR-fRf.js → domains-BSawReeu.js} +1 -1
  170. modoboa/frontend_dist/assets/{domains.store-ChZgLcqP.js → domains.store-D-vWCEIK.js} +1 -1
  171. modoboa/frontend_dist/assets/{filter-D7NrAf6a.js → filter-C82FUCw_.js} +1 -1
  172. modoboa/frontend_dist/assets/forwardRefs-cvcnlhoK.js +1 -0
  173. modoboa/frontend_dist/assets/global.store-DbkcI5o2.js +1 -0
  174. modoboa/frontend_dist/assets/{importExport-Dn9vYw7T.js → importExport-DzoL4Mvc.js} +1 -1
  175. modoboa/frontend_dist/assets/index-BImkz5Jx.js +984 -0
  176. modoboa/frontend_dist/assets/index-DuzUMVLM.js +1 -0
  177. modoboa/frontend_dist/assets/layout-C5FyYCHK.js +1 -0
  178. modoboa/frontend_dist/assets/{layout.store-BxBoBlgf.js → layout.store-NXWtFIwL.js} +1 -1
  179. modoboa/frontend_dist/assets/logos-BswdveCV.js +1 -0
  180. modoboa/frontend_dist/assets/{logs-DrTzylW7.js → logs-6CbtfaZS.js} +1 -1
  181. modoboa/frontend_dist/assets/{parameters-Lgiqp7aw.js → parameters-aSQiR7kN.js} +1 -1
  182. modoboa/frontend_dist/assets/{parameters.store-C9k9DuTj.js → parameters.store-CzQqVatx.js} +1 -1
  183. modoboa/frontend_dist/assets/permissions-DNoefz-n.js +1 -0
  184. modoboa/frontend_dist/assets/{ssrBoot-BsxW6uW4.js → ssrBoot-CKUX4kcb.js} +1 -1
  185. modoboa/frontend_dist/assets/{tag-CFK9dzMJ.js → tag-B_yWNNJD.js} +1 -1
  186. modoboa/frontend_dist/assets/transports-BDNB9wR5.js +1 -0
  187. modoboa/frontend_dist/assets/{webmail-KrD8ZhNM.js → webmail-CdU6CD9b.js} +1 -1
  188. modoboa/frontend_dist/index.html +1 -1
  189. modoboa/lib/email_utils.py +2 -2
  190. modoboa/lib/permissions.py +7 -0
  191. modoboa/lib/redis.py +1 -5
  192. modoboa/lib/test_runners.py +29 -0
  193. modoboa/lib/tests/__init__.py +5 -1
  194. modoboa/locale/br/LC_MESSAGES/django.po +87 -75
  195. modoboa/locale/cs/LC_MESSAGES/django.po +82 -74
  196. modoboa/locale/cs_CZ/LC_MESSAGES/django.po +145 -121
  197. modoboa/locale/de/LC_MESSAGES/django.mo +0 -0
  198. modoboa/locale/de/LC_MESSAGES/django.po +339 -651
  199. modoboa/locale/de_DE/LC_MESSAGES/django.po +87 -75
  200. modoboa/locale/el_GR/LC_MESSAGES/django.po +160 -135
  201. modoboa/locale/en/LC_MESSAGES/django.po +82 -74
  202. modoboa/locale/es/LC_MESSAGES/django.po +158 -131
  203. modoboa/locale/es_MX/LC_MESSAGES/django.po +82 -74
  204. modoboa/locale/fi/LC_MESSAGES/django.po +87 -75
  205. modoboa/locale/fr/LC_MESSAGES/django.mo +0 -0
  206. modoboa/locale/fr/LC_MESSAGES/django.po +469 -201
  207. modoboa/locale/hu/LC_MESSAGES/django.po +82 -74
  208. modoboa/locale/it/LC_MESSAGES/django.mo +0 -0
  209. modoboa/locale/it/LC_MESSAGES/django.po +148 -122
  210. modoboa/locale/ja_JP/LC_MESSAGES/django.mo +0 -0
  211. modoboa/locale/ja_JP/LC_MESSAGES/django.po +201 -334
  212. modoboa/locale/ka/LC_MESSAGES/django.po +82 -74
  213. modoboa/locale/nl_NL/LC_MESSAGES/django.po +160 -132
  214. modoboa/locale/no/LC_MESSAGES/django.po +82 -74
  215. modoboa/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
  216. modoboa/locale/pl_PL/LC_MESSAGES/django.po +172 -149
  217. modoboa/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  218. modoboa/locale/pt_BR/LC_MESSAGES/django.po +172 -144
  219. modoboa/locale/pt_PT/LC_MESSAGES/django.po +135 -112
  220. modoboa/locale/ro_RO/LC_MESSAGES/django.po +87 -75
  221. modoboa/locale/ru/LC_MESSAGES/django.po +142 -118
  222. modoboa/locale/si/LC_MESSAGES/django.po +82 -74
  223. modoboa/locale/sk/LC_MESSAGES/django.po +82 -74
  224. modoboa/locale/sk_SK/LC_MESSAGES/django.po +84 -76
  225. modoboa/locale/sl_SI/LC_MESSAGES/django.po +90 -76
  226. modoboa/locale/sv/LC_MESSAGES/django.mo +0 -0
  227. modoboa/locale/sv/LC_MESSAGES/django.po +172 -139
  228. modoboa/locale/tr/LC_MESSAGES/django.po +87 -75
  229. modoboa/locale/tr_TR/LC_MESSAGES/django.po +84 -74
  230. modoboa/locale/uk/LC_MESSAGES/django.po +82 -74
  231. modoboa/locale/zh/LC_MESSAGES/django.po +82 -74
  232. modoboa/locale/zh_CN/LC_MESSAGES/django.po +82 -74
  233. modoboa/locale/zh_TW/LC_MESSAGES/django.po +87 -75
  234. modoboa/parameters/api/v2/tests.py +2 -2
  235. modoboa/parameters/api/v2/viewsets.py +2 -0
  236. modoboa/policyd/tests.py +2 -0
  237. modoboa/urls_api_v2.py +6 -0
  238. {modoboa-2.4.10.dist-info → modoboa-2.5.0.dist-info}/METADATA +6 -4
  239. {modoboa-2.4.10.dist-info → modoboa-2.5.0.dist-info}/RECORD +244 -193
  240. modoboa/frontend_dist/assets/AccountAliasForm-DVXatAhB.js +0 -1
  241. modoboa/frontend_dist/assets/AccountEditView-DmvQjxpx.js +0 -1
  242. modoboa/frontend_dist/assets/AccountLayout-OGtZvlHR.js +0 -1
  243. modoboa/frontend_dist/assets/AccountPasswordSubForm-g3IEGrgM.js +0 -1
  244. modoboa/frontend_dist/assets/AccountView-DsxYqr3k.js +0 -1
  245. modoboa/frontend_dist/assets/AddressBook-3RoKiKon.js +0 -1
  246. modoboa/frontend_dist/assets/AdminLayout-CWfn8zaQ.js +0 -1
  247. modoboa/frontend_dist/assets/AlarmsView-Bheey-gp.css +0 -1
  248. modoboa/frontend_dist/assets/AlarmsView-D3Mh8ntf.js +0 -1
  249. modoboa/frontend_dist/assets/AliasEditView-C15eUZ11.js +0 -1
  250. modoboa/frontend_dist/assets/AliasView-Cyvc5vMb.js +0 -1
  251. modoboa/frontend_dist/assets/AuditTrailView-LI2XuLLn.js +0 -1
  252. modoboa/frontend_dist/assets/CalendarView-BpOlPh3f.js +0 -1
  253. modoboa/frontend_dist/assets/ComposeEmailForm-CNfI7ept.js +0 -1
  254. modoboa/frontend_dist/assets/ComposeEmailView-B866Xsrc.js +0 -1
  255. modoboa/frontend_dist/assets/ConfirmDialog-BvqxQsD1.js +0 -1
  256. modoboa/frontend_dist/assets/ConnectedLayout-BQ3ug6Jh.js +0 -1
  257. modoboa/frontend_dist/assets/CreationForm-C9Kh05ax.js +0 -1
  258. modoboa/frontend_dist/assets/DashboardView-Cw-gIcuB.js +0 -1
  259. modoboa/frontend_dist/assets/DomainAdminList-CsWUNKVk.js +0 -1
  260. modoboa/frontend_dist/assets/DomainEditView-DocxeOeW.js +0 -1
  261. modoboa/frontend_dist/assets/DomainView-Djc_0PsF.js +0 -5
  262. modoboa/frontend_dist/assets/DomainsView-B-Lxru7P.js +0 -1
  263. modoboa/frontend_dist/assets/DomainsView-DasJ0NdZ.css +0 -1
  264. modoboa/frontend_dist/assets/EmailField-BEKxuYni.js +0 -1
  265. modoboa/frontend_dist/assets/EmailView-BsR1Wes5.js +0 -1
  266. modoboa/frontend_dist/assets/EmptyLayout-BzPFOeLU.js +0 -1
  267. modoboa/frontend_dist/assets/FiltersView-5rmpC5cC.js +0 -1
  268. modoboa/frontend_dist/assets/ForwardEmailView-D7MbetcT.js +0 -1
  269. modoboa/frontend_dist/assets/IdentitiesView-BqjD9Lue.js +0 -1
  270. modoboa/frontend_dist/assets/InformationView-CghcvPn2.js +0 -1
  271. modoboa/frontend_dist/assets/InformationView-U5Ww-Sx1.css +0 -1
  272. modoboa/frontend_dist/assets/MailboxView-T_p-_ZtJ.js +0 -1
  273. modoboa/frontend_dist/assets/MenuItems-kHCMzR5E.js +0 -1
  274. modoboa/frontend_dist/assets/MessagesView-Cerv3xsy.js +0 -1
  275. modoboa/frontend_dist/assets/MigrationsView-7kjqPyYU.js +0 -1
  276. modoboa/frontend_dist/assets/ParametersView-DspBxVMV.js +0 -1
  277. modoboa/frontend_dist/assets/ParametersView-Dy0H5ep1.js +0 -1
  278. modoboa/frontend_dist/assets/ProviderEditView-DDLMOylC.js +0 -1
  279. modoboa/frontend_dist/assets/ProviderGeneralForm-BwOSKNHK.js +0 -1
  280. modoboa/frontend_dist/assets/ProvidersView-C99UD0WB.js +0 -1
  281. modoboa/frontend_dist/assets/ReplyEmailView-DAPBHldd.js +0 -1
  282. modoboa/frontend_dist/assets/ResourcesForm-D87PHeH0.js +0 -1
  283. modoboa/frontend_dist/assets/SettingsView-OxDo9wNd.js +0 -6
  284. modoboa/frontend_dist/assets/StatisticsView-CM__Eqku.js +0 -1
  285. modoboa/frontend_dist/assets/TimeSerieChart-C6j0uYR_.js +0 -1
  286. modoboa/frontend_dist/assets/UserLayout-CckCGnPS.js +0 -1
  287. modoboa/frontend_dist/assets/VAlert-B7mzOJIO.js +0 -1
  288. modoboa/frontend_dist/assets/VApp-BKxnjOoi.js +0 -1
  289. modoboa/frontend_dist/assets/VAutocomplete-Cc4_tcl1.js +0 -1
  290. modoboa/frontend_dist/assets/VAvatar-BAgTUIvX.js +0 -1
  291. modoboa/frontend_dist/assets/VCard-DFWiFORP.js +0 -1
  292. modoboa/frontend_dist/assets/VCheckbox-CKsH_vq3.js +0 -1
  293. modoboa/frontend_dist/assets/VChip-nZ0uhY7t.js +0 -1
  294. modoboa/frontend_dist/assets/VColorPicker-Os2aeP6J.js +0 -1
  295. modoboa/frontend_dist/assets/VContainer-Btam4lk2.js +0 -1
  296. modoboa/frontend_dist/assets/VDataTable-D_0_xJTl.js +0 -1
  297. modoboa/frontend_dist/assets/VDataTableServer-BWTt4Mzi.js +0 -1
  298. modoboa/frontend_dist/assets/VDataTableVirtual-BwVmkt4u.js +0 -1
  299. modoboa/frontend_dist/assets/VExpansionPanels-B5D6GOa3.js +0 -1
  300. modoboa/frontend_dist/assets/VFileInput-Cv9DIPki.js +0 -1
  301. modoboa/frontend_dist/assets/VForm-CpoZf60D.js +0 -1
  302. modoboa/frontend_dist/assets/VMenu-B_dVqOmo.js +0 -1
  303. modoboa/frontend_dist/assets/VPicker-CXkIGEze.js +0 -1
  304. modoboa/frontend_dist/assets/VProgressCircular-CrEXxs7k.js +0 -1
  305. modoboa/frontend_dist/assets/VRadioGroup-D8ypjYOO.js +0 -1
  306. modoboa/frontend_dist/assets/VSelect-CS51PDEt.js +0 -1
  307. modoboa/frontend_dist/assets/VSelectionControl-DiOqtY38.js +0 -1
  308. modoboa/frontend_dist/assets/VSheet-5VVWtHvs.js +0 -1
  309. modoboa/frontend_dist/assets/VSpacer-C6PZ3X24.js +0 -1
  310. modoboa/frontend_dist/assets/VSwitch-Chg5o-Cp.js +0 -1
  311. modoboa/frontend_dist/assets/VTable-KsiZ3cBz.js +0 -1
  312. modoboa/frontend_dist/assets/VTabs-tNrJIYO0.js +0 -1
  313. modoboa/frontend_dist/assets/VTextField-C-J20yj_.css +0 -1
  314. modoboa/frontend_dist/assets/VTextField-CLwRV0Cb.js +0 -1
  315. modoboa/frontend_dist/assets/VTextarea-Di8jbl8m.js +0 -1
  316. modoboa/frontend_dist/assets/VToolbar-CGwhgdmI.js +0 -1
  317. modoboa/frontend_dist/assets/VWindowItem-wWSFAGI-.js +0 -1
  318. modoboa/frontend_dist/assets/WebmailLayout-DsYThBrz.js +0 -1
  319. modoboa/frontend_dist/assets/admin-CJVLMHh9.js +0 -1
  320. modoboa/frontend_dist/assets/forwardRefs-Cpc3YYl6.js +0 -1
  321. modoboa/frontend_dist/assets/global.store-DUP26-A5.js +0 -1
  322. modoboa/frontend_dist/assets/index-DV9Li2cg.js +0 -852
  323. modoboa/frontend_dist/assets/index-DzL89N4E.js +0 -1
  324. modoboa/frontend_dist/assets/layout-CHO37cA6.js +0 -1
  325. modoboa/frontend_dist/assets/permissions-mL5hLHcW.js +0 -1
  326. modoboa/frontend_dist/assets/transports-TO08iTXJ.js +0 -1
  327. {modoboa-2.4.10.data → modoboa-2.5.0.data}/scripts/modoboa-admin.py +0 -0
  328. {modoboa-2.4.10.dist-info → modoboa-2.5.0.dist-info}/WHEEL +0 -0
  329. {modoboa-2.4.10.dist-info → modoboa-2.5.0.dist-info}/entry_points.txt +0 -0
  330. {modoboa-2.4.10.dist-info → modoboa-2.5.0.dist-info}/licenses/LICENSE +0 -0
  331. {modoboa-2.4.10.dist-info → modoboa-2.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,99 @@
1
+ from django.contrib.sites import models as sites_models
2
+ from django.core import mail
3
+ from django.core.management.base import BaseCommand
4
+ from django.template.loader import render_to_string
5
+ from django.utils.translation import gettext as _
6
+
7
+ from modoboa.admin.models import Domain
8
+ from modoboa.core.models import User
9
+ from modoboa.parameters import tools as param_tools
10
+ from ...models import Msgrcpt
11
+ from ...sql_connector import SQLconnector
12
+
13
+
14
+ class Command(BaseCommand):
15
+ help = "Amavis notification tool" # NOQA:A003
16
+
17
+ sender = None
18
+ baseurl = None
19
+ listingurl = None
20
+
21
+ def add_arguments(self, parser):
22
+ """Add extra arguments to command line."""
23
+ parser.add_argument(
24
+ "--smtp_host",
25
+ type=str,
26
+ default="localhost",
27
+ help="The address of the SMTP server used to send notifications",
28
+ )
29
+ parser.add_argument(
30
+ "--smtp_port",
31
+ type=int,
32
+ default=25,
33
+ help=(
34
+ "The listening port of the SMTP server used to send " "notifications"
35
+ ),
36
+ )
37
+ parser.add_argument(
38
+ "--verbose", action="store_true", help="Activate verbose mode"
39
+ )
40
+
41
+ def handle(self, *args, **options):
42
+ self.options = options
43
+ self.notify_admins_pending_requests()
44
+
45
+ def _build_message(self, rcpt, total, reqs):
46
+ """Build new EmailMessage instance."""
47
+ if self.options["verbose"]:
48
+ print(f"Sending notification to {rcpt}")
49
+ context = {
50
+ "total": total,
51
+ "requests": reqs,
52
+ "baseurl": self.baseurl,
53
+ "listingurl": self.listingurl,
54
+ }
55
+ content = render_to_string(
56
+ "amavis/notifications/pending_requests.html", context
57
+ )
58
+ msg = mail.EmailMessage(
59
+ _("[modoboa] Pending release requests"), content, self.sender, [rcpt]
60
+ )
61
+ return msg
62
+
63
+ def notify_admins_pending_requests(self):
64
+ self.sender = param_tools.get_global_parameter(
65
+ "notifications_sender", app="amavis"
66
+ )
67
+ self.baseurl = f"https://{sites_models.Site.objects.get_current().domain}"
68
+ self.listingurl = f"{self.baseurl}/user/quarantine?requests=1"
69
+ messages = []
70
+ # Check domain administators first.
71
+ for da in User.objects.filter(groups__name="DomainAdmins"):
72
+ if not hasattr(da, "mailbox"):
73
+ continue
74
+ rcpt = da.mailbox.full_address
75
+ reqs = SQLconnector().get_domains_pending_requests(
76
+ Domain.objects.get_for_admin(da).values_list("name", flat=True)
77
+ )
78
+ total = reqs.count()
79
+ reqs = reqs.all()[:10]
80
+ if reqs.count():
81
+ messages.append(self._build_message(rcpt, total, reqs))
82
+
83
+ # Then super administators.
84
+ reqs = Msgrcpt.objects.filter(rs="p")
85
+ total = reqs.count()
86
+ if total:
87
+ reqs = reqs.all()[:10]
88
+ for su in User.objects.filter(is_superuser=True):
89
+ if not hasattr(su, "mailbox"):
90
+ continue
91
+ rcpt = su.mailbox.full_address
92
+ messages.append(self._build_message(rcpt, total, reqs))
93
+
94
+ # Finally, send emails.
95
+ if not len(messages):
96
+ return
97
+ kwargs = {"host": self.options["smtp_host"], "port": self.options["smtp_port"]}
98
+ with mail.get_connection(**kwargs) as connection:
99
+ connection.send_messages(messages)
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env python
2
+
3
+
4
+ import time
5
+
6
+ from django.core.management.base import BaseCommand
7
+ from django.db.models import Count
8
+
9
+ from modoboa.parameters import tools as param_tools
10
+ from ...models import Maddr, Msgrcpt, Msgs
11
+
12
+
13
+ class Command(BaseCommand):
14
+ args = ""
15
+ help = "Amavis quarantine cleanup" # NOQA:A003
16
+
17
+ def add_arguments(self, parser):
18
+ """Add extra arguments to command line."""
19
+ parser.add_argument(
20
+ "--debug", action="store_true", default=False, help="Activate debug output"
21
+ )
22
+ parser.add_argument(
23
+ "--verbose",
24
+ action="store_true",
25
+ default=False,
26
+ help="Display informational messages",
27
+ )
28
+
29
+ def __vprint(self, msg):
30
+ if not self.verbose:
31
+ return
32
+ print(msg)
33
+
34
+ def handle(self, *args, **options):
35
+ if options["debug"]:
36
+ import logging
37
+
38
+ log = logging.getLogger("django.db.backends")
39
+ log.setLevel(logging.DEBUG)
40
+ log.addHandler(logging.StreamHandler())
41
+ self.verbose = options["verbose"]
42
+
43
+ conf = dict(param_tools.get_global_parameters("amavis"))
44
+
45
+ flags = ["D"]
46
+ if conf["released_msgs_cleanup"]:
47
+ flags += ["R"]
48
+
49
+ self.__vprint("Deleting marked messages...")
50
+ ids = Msgrcpt.objects.filter(rs__in=flags).values("mail_id").distinct()
51
+ for msg in Msgs.objects.filter(mail_id__in=ids):
52
+ if not msg.msgrcpt_set.exclude(rs__in=flags).count():
53
+ msg.delete()
54
+
55
+ self.__vprint(
56
+ "Deleting messages older than {} days...".format(conf["max_messages_age"])
57
+ )
58
+ limit = int(time.time()) - (conf["max_messages_age"] * 24 * 3600)
59
+ while True:
60
+ qset = Msgs.objects.filter(
61
+ pk__in=list(
62
+ Msgs.objects.filter(time_num__lt=limit).values_list(
63
+ "pk", flat=True
64
+ )[:5000]
65
+ )
66
+ )
67
+ if not qset.exists():
68
+ break
69
+ qset.delete()
70
+
71
+ self.__vprint("Deleting unreferenced e-mail addresses...")
72
+ while True:
73
+ res = (
74
+ Maddr.objects.annotate(
75
+ msgs_count=Count("msgs"), msgrcpt_count=Count("msgrcpt")
76
+ )
77
+ .filter(msgs_count=0, msgrcpt_count=0)
78
+ .values_list("id", flat=True)[:100000]
79
+ )
80
+ if not res.exists():
81
+ break
82
+ Maddr.objects.filter(id__in=list(res)).delete()
83
+
84
+ self.__vprint("Done.")
@@ -0,0 +1,340 @@
1
+ from django.db import models, migrations
2
+
3
+
4
+ class Migration(migrations.Migration):
5
+
6
+ dependencies = []
7
+
8
+ operations = [
9
+ migrations.CreateModel(
10
+ name="Maddr",
11
+ fields=[
12
+ ("partition_tag", models.IntegerField(default=0)),
13
+ ("id", models.BigIntegerField(serialize=False, primary_key=True)),
14
+ ("email", models.CharField(unique=True, max_length=255)),
15
+ ("domain", models.CharField(max_length=765)),
16
+ ],
17
+ options={
18
+ "db_table": "maddr",
19
+ "managed": False,
20
+ },
21
+ bases=(models.Model,),
22
+ ),
23
+ migrations.CreateModel(
24
+ name="Mailaddr",
25
+ fields=[
26
+ ("id", models.IntegerField(serialize=False, primary_key=True)),
27
+ ("priority", models.IntegerField()),
28
+ ("email", models.CharField(unique=True, max_length=255)),
29
+ ],
30
+ options={
31
+ "db_table": "mailaddr",
32
+ "managed": False,
33
+ },
34
+ bases=(models.Model,),
35
+ ),
36
+ migrations.CreateModel(
37
+ name="Msgs",
38
+ fields=[
39
+ ("partition_tag", models.IntegerField(default=0)),
40
+ (
41
+ "mail_id",
42
+ models.CharField(max_length=12, serialize=False, primary_key=True),
43
+ ),
44
+ ("secret_id", models.CharField(max_length=12, blank=True)),
45
+ ("am_id", models.CharField(max_length=60)),
46
+ ("time_num", models.IntegerField()),
47
+ ("time_iso", models.CharField(max_length=48)),
48
+ ("policy", models.CharField(max_length=765, blank=True)),
49
+ ("client_addr", models.CharField(max_length=765, blank=True)),
50
+ ("size", models.IntegerField()),
51
+ ("originating", models.CharField(max_length=3)),
52
+ ("content", models.CharField(max_length=1, blank=True)),
53
+ ("quar_type", models.CharField(max_length=1, blank=True)),
54
+ ("quar_loc", models.CharField(max_length=255, blank=True)),
55
+ ("dsn_sent", models.CharField(max_length=3, blank=True)),
56
+ ("spam_level", models.FloatField(null=True, blank=True)),
57
+ ("message_id", models.CharField(max_length=765, blank=True)),
58
+ ("from_addr", models.CharField(max_length=765, blank=True)),
59
+ ("subject", models.CharField(max_length=765, blank=True)),
60
+ ("host", models.CharField(max_length=765)),
61
+ ],
62
+ options={
63
+ "db_table": "msgs",
64
+ "managed": False,
65
+ },
66
+ bases=(models.Model,),
67
+ ),
68
+ migrations.CreateModel(
69
+ name="Msgrcpt",
70
+ fields=[
71
+ ("partition_tag", models.IntegerField(default=0)),
72
+ (
73
+ "mail",
74
+ models.ForeignKey(
75
+ primary_key=True,
76
+ serialize=False,
77
+ to="amavis.Msgs",
78
+ on_delete=models.CASCADE,
79
+ ),
80
+ ),
81
+ ("rseqnum", models.IntegerField(default=0)),
82
+ ("is_local", models.CharField(max_length=3)),
83
+ ("content", models.CharField(max_length=3)),
84
+ ("ds", models.CharField(max_length=3)),
85
+ ("rs", models.CharField(max_length=3)),
86
+ ("bl", models.CharField(max_length=3, blank=True)),
87
+ ("wl", models.CharField(max_length=3, blank=True)),
88
+ ("bspam_level", models.FloatField(null=True, blank=True)),
89
+ ("smtp_resp", models.CharField(max_length=765, blank=True)),
90
+ ],
91
+ options={
92
+ "db_table": "msgrcpt",
93
+ "managed": False,
94
+ },
95
+ bases=(models.Model,),
96
+ ),
97
+ migrations.CreateModel(
98
+ name="Policy",
99
+ fields=[
100
+ (
101
+ "id",
102
+ models.AutoField(
103
+ verbose_name="ID",
104
+ serialize=False,
105
+ auto_created=True,
106
+ primary_key=True,
107
+ ),
108
+ ),
109
+ ("policy_name", models.CharField(max_length=32, blank=True)),
110
+ ("virus_lover", models.CharField(max_length=3, null=True, blank=True)),
111
+ ("spam_lover", models.CharField(max_length=3, null=True, blank=True)),
112
+ (
113
+ "unchecked_lover",
114
+ models.CharField(max_length=3, null=True, blank=True),
115
+ ),
116
+ (
117
+ "banned_files_lover",
118
+ models.CharField(max_length=3, null=True, blank=True),
119
+ ),
120
+ (
121
+ "bad_header_lover",
122
+ models.CharField(max_length=3, null=True, blank=True),
123
+ ),
124
+ (
125
+ "bypass_virus_checks",
126
+ models.CharField(
127
+ default=b"",
128
+ choices=[(b"N", "yes"), (b"Y", "no"), (b"", "default")],
129
+ max_length=3,
130
+ help_text="Bypass virus checks or not. Choose 'default' to use global settings.",
131
+ null=True,
132
+ verbose_name="Virus filter",
133
+ ),
134
+ ),
135
+ (
136
+ "bypass_spam_checks",
137
+ models.CharField(
138
+ default=b"",
139
+ choices=[(b"N", "yes"), (b"Y", "no"), (b"", "default")],
140
+ max_length=3,
141
+ help_text="Bypass spam checks or not. Choose 'default' to use global settings.",
142
+ null=True,
143
+ verbose_name="Spam filter",
144
+ ),
145
+ ),
146
+ (
147
+ "bypass_banned_checks",
148
+ models.CharField(
149
+ default=b"",
150
+ choices=[(b"N", "yes"), (b"Y", "no"), (b"", "default")],
151
+ max_length=3,
152
+ help_text="Bypass banned checks or not. Choose 'default' to use global settings.",
153
+ null=True,
154
+ verbose_name="Banned filter",
155
+ ),
156
+ ),
157
+ (
158
+ "bypass_header_checks",
159
+ models.CharField(max_length=3, null=True, blank=True),
160
+ ),
161
+ (
162
+ "virus_quarantine_to",
163
+ models.CharField(max_length=192, null=True, blank=True),
164
+ ),
165
+ (
166
+ "spam_quarantine_to",
167
+ models.CharField(max_length=192, null=True, blank=True),
168
+ ),
169
+ (
170
+ "banned_quarantine_to",
171
+ models.CharField(max_length=192, null=True, blank=True),
172
+ ),
173
+ (
174
+ "unchecked_quarantine_to",
175
+ models.CharField(max_length=192, null=True, blank=True),
176
+ ),
177
+ (
178
+ "bad_header_quarantine_to",
179
+ models.CharField(max_length=192, null=True, blank=True),
180
+ ),
181
+ (
182
+ "clean_quarantine_to",
183
+ models.CharField(max_length=192, null=True, blank=True),
184
+ ),
185
+ (
186
+ "archive_quarantine_to",
187
+ models.CharField(max_length=192, null=True, blank=True),
188
+ ),
189
+ ("spam_tag_level", models.FloatField(null=True, blank=True)),
190
+ ("spam_tag2_level", models.FloatField(null=True, blank=True)),
191
+ ("spam_tag3_level", models.FloatField(null=True, blank=True)),
192
+ ("spam_kill_level", models.FloatField(null=True, blank=True)),
193
+ ("spam_dsn_cutoff_level", models.FloatField(null=True, blank=True)),
194
+ (
195
+ "spam_quarantine_cutoff_level",
196
+ models.FloatField(null=True, blank=True),
197
+ ),
198
+ (
199
+ "addr_extension_virus",
200
+ models.CharField(max_length=192, null=True, blank=True),
201
+ ),
202
+ (
203
+ "addr_extension_spam",
204
+ models.CharField(max_length=192, null=True, blank=True),
205
+ ),
206
+ (
207
+ "addr_extension_banned",
208
+ models.CharField(max_length=192, null=True, blank=True),
209
+ ),
210
+ (
211
+ "addr_extension_bad_header",
212
+ models.CharField(max_length=192, null=True, blank=True),
213
+ ),
214
+ (
215
+ "warnvirusrecip",
216
+ models.CharField(max_length=3, null=True, blank=True),
217
+ ),
218
+ (
219
+ "warnbannedrecip",
220
+ models.CharField(max_length=3, null=True, blank=True),
221
+ ),
222
+ (
223
+ "warnbadhrecip",
224
+ models.CharField(max_length=3, null=True, blank=True),
225
+ ),
226
+ (
227
+ "newvirus_admin",
228
+ models.CharField(max_length=192, null=True, blank=True),
229
+ ),
230
+ (
231
+ "virus_admin",
232
+ models.CharField(max_length=192, null=True, blank=True),
233
+ ),
234
+ (
235
+ "banned_admin",
236
+ models.CharField(max_length=192, null=True, blank=True),
237
+ ),
238
+ (
239
+ "bad_header_admin",
240
+ models.CharField(max_length=192, null=True, blank=True),
241
+ ),
242
+ ("spam_admin", models.CharField(max_length=192, null=True, blank=True)),
243
+ (
244
+ "spam_subject_tag",
245
+ models.CharField(max_length=192, null=True, blank=True),
246
+ ),
247
+ (
248
+ "spam_subject_tag2",
249
+ models.CharField(
250
+ default=None,
251
+ max_length=192,
252
+ blank=True,
253
+ help_text="Modify spam subject using the specified text. Choose 'default' to use global settings.",
254
+ null=True,
255
+ verbose_name="Spam marker",
256
+ ),
257
+ ),
258
+ (
259
+ "spam_subject_tag3",
260
+ models.CharField(max_length=192, null=True, blank=True),
261
+ ),
262
+ ("message_size_limit", models.IntegerField(null=True, blank=True)),
263
+ (
264
+ "banned_rulenames",
265
+ models.CharField(max_length=192, null=True, blank=True),
266
+ ),
267
+ (
268
+ "disclaimer_options",
269
+ models.CharField(max_length=192, null=True, blank=True),
270
+ ),
271
+ (
272
+ "forward_method",
273
+ models.CharField(max_length=192, null=True, blank=True),
274
+ ),
275
+ (
276
+ "sa_userconf",
277
+ models.CharField(max_length=192, null=True, blank=True),
278
+ ),
279
+ (
280
+ "sa_username",
281
+ models.CharField(max_length=192, null=True, blank=True),
282
+ ),
283
+ ],
284
+ options={
285
+ "db_table": "policy",
286
+ "managed": False,
287
+ },
288
+ bases=(models.Model,),
289
+ ),
290
+ migrations.CreateModel(
291
+ name="Quarantine",
292
+ fields=[
293
+ ("partition_tag", models.IntegerField(default=0)),
294
+ (
295
+ "mail",
296
+ models.ForeignKey(
297
+ primary_key=True,
298
+ serialize=False,
299
+ to="amavis.Msgs",
300
+ on_delete=models.CASCADE,
301
+ ),
302
+ ),
303
+ ("chunk_ind", models.IntegerField()),
304
+ ("mail_text", models.TextField()),
305
+ ],
306
+ options={
307
+ "ordering": ["-mail__time_num"],
308
+ "db_table": "quarantine",
309
+ "managed": False,
310
+ },
311
+ bases=(models.Model,),
312
+ ),
313
+ migrations.CreateModel(
314
+ name="Users",
315
+ fields=[
316
+ ("id", models.AutoField(serialize=False, primary_key=True)),
317
+ ("priority", models.IntegerField()),
318
+ ("email", models.CharField(unique=True, max_length=255)),
319
+ ("fullname", models.CharField(max_length=765, blank=True)),
320
+ ],
321
+ options={
322
+ "db_table": "users",
323
+ "managed": False,
324
+ },
325
+ bases=(models.Model,),
326
+ ),
327
+ migrations.CreateModel(
328
+ name="Wblist",
329
+ fields=[
330
+ ("rid", models.IntegerField(serialize=False, primary_key=True)),
331
+ ("sid", models.IntegerField(primary_key=True)),
332
+ ("wb", models.CharField(max_length=30)),
333
+ ],
334
+ options={
335
+ "db_table": "wblist",
336
+ "managed": False,
337
+ },
338
+ bases=(models.Model,),
339
+ ),
340
+ ]
File without changes