modoboa 2.5.0__py3-none-any.whl → 2.6.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.
- modoboa/admin/api/v2/serializers.py +1 -1
- modoboa/admin/models/domain.py +1 -1
- modoboa/admin/models/mixins.py +3 -1
- modoboa/amavis/serializers.py +1 -1
- modoboa/autoconfig/__init__.py +0 -0
- modoboa/autoconfig/apps.py +6 -0
- modoboa/autoconfig/templates/autoconfig/autoconfig.xml +24 -0
- modoboa/autoconfig/templates/autoconfig/autodiscover.xml +27 -0
- modoboa/autoconfig/tests.py +38 -0
- modoboa/autoconfig/urls.py +21 -0
- modoboa/autoconfig/views.py +109 -0
- modoboa/autoreply/api/v2/tests.py +4 -4
- modoboa/calendars/tests.py +8 -8
- modoboa/contacts/tests.py +5 -7
- modoboa/core/api/v1/tests.py +2 -2
- modoboa/core/api/v2/views.py +3 -1
- modoboa/core/commands/deploy.py +3 -0
- modoboa/core/commands/templates/settings.py.tpl +26 -12
- modoboa/core/models.py +1 -1
- modoboa/core/tests/test_ldap.py +2 -0
- modoboa/core/views/auth.py +27 -8
- modoboa/frontend_dist/assets/{AccountAliasForm-BuSy_1n9.js → AccountAliasForm-Bu1I8sLg.js} +1 -1
- modoboa/frontend_dist/assets/{AccountEditView-qdJmLM_e.js → AccountEditView-YOpDW-Ob.js} +1 -1
- modoboa/frontend_dist/assets/AccountLayout-Cf_FVfvJ.js +1 -0
- modoboa/frontend_dist/assets/{AccountPasswordSubForm-DZGt_Xgq.js → AccountPasswordSubForm-B9X5wAXp.js} +1 -1
- modoboa/frontend_dist/assets/{AccountView-CO65y0vZ.js → AccountView-DCqbD7oi.js} +1 -1
- modoboa/frontend_dist/assets/{AddressBook-BZNUlhek.js → AddressBook-B53LXIsD.js} +1 -1
- modoboa/frontend_dist/assets/AdminLayout-DX-RXYiU.js +1 -0
- modoboa/frontend_dist/assets/AlarmsView-C0KvogOj.js +1 -0
- modoboa/frontend_dist/assets/AliasEditView-BiMPygn9.js +1 -0
- modoboa/frontend_dist/assets/AliasEditView-CYDSiX8l.css +1 -0
- modoboa/frontend_dist/assets/AliasRecipientForm-BhQfATiS.js +1 -0
- modoboa/frontend_dist/assets/{AliasView-GOJ5lyQH.js → AliasView-eIct4lMV.js} +1 -1
- modoboa/frontend_dist/assets/{AuditTrailView-fbXmq70e.js → AuditTrailView-FiUNTjpE.js} +1 -1
- modoboa/frontend_dist/assets/{CalendarView-LlQQNEPL.js → CalendarView-DbWVDoWq.js} +1 -1
- modoboa/frontend_dist/assets/{ChoiceField-B3ReQHVe.js → ChoiceField-17aCFpF6.js} +1 -1
- modoboa/frontend_dist/assets/{ComposeEmailForm-Bs1fZXAL.js → ComposeEmailForm-B-BP3lzX.js} +1 -1
- modoboa/frontend_dist/assets/ComposeEmailView-6JrFhK1W.js +1 -0
- modoboa/frontend_dist/assets/ConfirmDialog-Dr0i2kqK.js +1 -0
- modoboa/frontend_dist/assets/ConnectedLayout-irTI2ekJ.js +1 -0
- modoboa/frontend_dist/assets/{CreationForm-ORg3fazt.js → CreationForm-BZMhQOez.js} +1 -1
- modoboa/frontend_dist/assets/DashboardView-CBpsEG3P.js +1 -0
- modoboa/frontend_dist/assets/{DomainAdminList-DVn9x0rB.js → DomainAdminList-BikGujRD.js} +1 -1
- modoboa/frontend_dist/assets/{DomainEditView-nAoL64D_.js → DomainEditView-SOvfeZWo.js} +1 -1
- modoboa/frontend_dist/assets/{DomainTransportForm-CA-DNUxX.js → DomainTransportForm-CmFZ1Cxm.js} +1 -1
- modoboa/frontend_dist/assets/{DomainView-CdXPpwJG.js → DomainView-DasOm4jM.js} +3 -3
- modoboa/frontend_dist/assets/{DomainsView-B_59gowf.js → DomainsView-DVJA4-oN.js} +1 -1
- modoboa/frontend_dist/assets/{EmailField-CwcwI5xW.js → EmailField-DpBYkqam.js} +1 -1
- modoboa/frontend_dist/assets/{EmailView-BshxcfAK.js → EmailView-D9vO7HHB.js} +1 -1
- modoboa/frontend_dist/assets/EmptyLayout-Dz3F8c7x.js +1 -0
- modoboa/frontend_dist/assets/{FiltersView-Cf20MSTK.js → FiltersView-FjdtF4HL.js} +1 -1
- modoboa/frontend_dist/assets/ForwardEmailView-DF5BQJjL.js +1 -0
- modoboa/frontend_dist/assets/{HtmlEditor-Bh4c689R.js → HtmlEditor-Zn0wjDog.js} +1 -1
- modoboa/frontend_dist/assets/{IdentitiesView-BXAuU1YX.js → IdentitiesView-Cf5eQoKA.js} +1 -1
- modoboa/frontend_dist/assets/{IdentitiesView-DPrrRMS5.css → IdentitiesView-D3AAiZLZ.css} +1 -1
- modoboa/frontend_dist/assets/{InformationView-Cn5FZW7H.js → InformationView-gEYTQ37R.js} +1 -1
- modoboa/frontend_dist/assets/{LoadingData-CdVvm4FI.js → LoadingData-Cxd490P6.js} +1 -1
- modoboa/frontend_dist/assets/LoginCallbackView-C9zhejHH.js +1 -0
- modoboa/frontend_dist/assets/{LoginView-tHIR4Adc.js → LoginView-sWEH834U.js} +1 -1
- modoboa/frontend_dist/assets/{MailboxView-B-aI4XBq.css → MailboxView-CfStlWhk.css} +1 -1
- modoboa/frontend_dist/assets/MailboxView-Dn3iDym9.js +1 -0
- modoboa/frontend_dist/assets/{MenuItems-PXjiG-fs.js → MenuItems-BRChEdLp.js} +1 -1
- modoboa/frontend_dist/assets/{MessageView-Cy4STShm.js → MessageView-CDbJxbxm.js} +1 -1
- modoboa/frontend_dist/assets/{MessagesView-DdkuEgfX.js → MessagesView-C_vBxVzN.js} +1 -1
- modoboa/frontend_dist/assets/{MigrationsView-CidSEjCF.js → MigrationsView-D6peiQuR.js} +1 -1
- modoboa/frontend_dist/assets/{ParametersForm-CAv4SH-E.js → ParametersForm-Dip8Sobe.js} +1 -1
- modoboa/frontend_dist/assets/ParametersView-CwI0-9kV.js +1 -0
- modoboa/frontend_dist/assets/ParametersView-wFKfiEVR.js +1 -0
- modoboa/frontend_dist/assets/{ProviderEditView-CrltAQXl.js → ProviderEditView-EH2NSz3x.js} +1 -1
- modoboa/frontend_dist/assets/{ProviderGeneralForm-BYAzVnXM.js → ProviderGeneralForm-CAVNOJp6.js} +1 -1
- modoboa/frontend_dist/assets/{ProvidersView-osjIY4Ex.js → ProvidersView-BoH99d3a.js} +1 -1
- modoboa/frontend_dist/assets/QuarantineLayout--4g9urq2.js +1 -0
- modoboa/frontend_dist/assets/{QuarantineView-D8Qg0MXA.js → QuarantineView-BDzDrWwK.js} +1 -1
- modoboa/frontend_dist/assets/ReplyEmailView-D0VgYBnw.js +1 -0
- modoboa/frontend_dist/assets/ResourcesForm-C1YGkT8i.js +1 -0
- modoboa/frontend_dist/assets/SelfServiceLayout-BYkSLc4n.js +1 -0
- modoboa/frontend_dist/assets/{SettingsView-9iNcDhkI.js → SettingsView-Cy5O-88Y.js} +1 -1
- modoboa/frontend_dist/assets/{StatisticsView-cHsPyGkL.js → StatisticsView-DtlBQK9z.js} +1 -1
- modoboa/frontend_dist/assets/{TimeSerieChart--V83dcJ9.js → TimeSerieChart-DNjvmMDE.js} +1 -1
- modoboa/frontend_dist/assets/{TimeSerieChart-CxiwMzE8.css → TimeSerieChart-Dn6Wznn8.css} +1 -1
- modoboa/frontend_dist/assets/UserLayout-Cgqq7HVi.js +1 -0
- modoboa/frontend_dist/assets/{VAlert-BuaaYN2h.js → VAlert-x6n3drjw.js} +1 -1
- modoboa/frontend_dist/assets/{VApp-CKP-6zGP.js → VApp-C74A9rX5.js} +1 -1
- modoboa/frontend_dist/assets/{VAutocomplete-Dwv6_Rzq.js → VAutocomplete-Bg2AlW_n.js} +1 -1
- modoboa/frontend_dist/assets/{VAvatar-Cmga0vj6.js → VAvatar-J563boKh.js} +1 -1
- modoboa/frontend_dist/assets/{VBadge-CixeK87a.js → VBadge-CtEsXuih.js} +1 -1
- modoboa/frontend_dist/assets/{VCard-CxH9DWoK.js → VCard-CJ2oGh_i.js} +1 -1
- modoboa/frontend_dist/assets/{VCheckbox-62GOpvvP.js → VCheckbox-VicuXIJq.js} +1 -1
- modoboa/frontend_dist/assets/{VCheckboxBtn-DMoNtKT8.js → VCheckboxBtn-CLh3m66z.js} +1 -1
- modoboa/frontend_dist/assets/{VChip-D_styETR.js → VChip-DvxO74Mw.js} +1 -1
- modoboa/frontend_dist/assets/VColorPicker-DcVohVWE.js +1 -0
- modoboa/frontend_dist/assets/{VContainer-B46caNs1.js → VContainer-L2EoH3dT.js} +1 -1
- modoboa/frontend_dist/assets/{VDataTable-Bh8NbVSx.js → VDataTable-CAT0QYJz.js} +1 -1
- modoboa/frontend_dist/assets/{VDataTableServer-BDR5hOmo.js → VDataTableServer-DP13Fhfa.js} +1 -1
- modoboa/frontend_dist/assets/{VDataTableVirtual-BOQlNtIG.js → VDataTableVirtual-LVNemzH7.js} +1 -1
- modoboa/frontend_dist/assets/{VDialog-BcTg7w6P.js → VDialog-CaQnQSDn.js} +1 -1
- modoboa/frontend_dist/assets/{VExpansionPanels-BmH5Jl2Z.js → VExpansionPanels-Dnwgt5uT.js} +1 -1
- modoboa/frontend_dist/assets/{VFileInput-BC4yAygd.js → VFileInput-z44hJIWr.js} +1 -1
- modoboa/frontend_dist/assets/{VForm-D5iPGkde.js → VForm-BwTUBf4u.js} +1 -1
- modoboa/frontend_dist/assets/{VInput-CoDJzvaW.js → VInput-Dpmea5z9.js} +1 -1
- modoboa/frontend_dist/assets/{VMenu-gUG70-zD.js → VMenu-DDmBlbM8.js} +1 -1
- modoboa/frontend_dist/assets/{VPicker-BXuKT3zB.js → VPicker-Dz7GbXwU.js} +1 -1
- modoboa/frontend_dist/assets/{VProgressCircular-BtOPiGCg.js → VProgressCircular-CtqQON49.js} +1 -1
- modoboa/frontend_dist/assets/{VRadioGroup-DIFZKSn-.js → VRadioGroup-WW8uMAv4.js} +1 -1
- modoboa/frontend_dist/assets/{VRow-ozg66L7j.js → VRow-CAbOSEHS.js} +1 -1
- modoboa/frontend_dist/assets/{VSelect-C3RjAa45.js → VSelect-Cdh0qO5m.js} +1 -1
- modoboa/frontend_dist/assets/{VSelectionControl-zyz-fJvC.js → VSelectionControl-BN-zQ3C6.js} +1 -1
- modoboa/frontend_dist/assets/{VSheet-BNx2X4Mk.js → VSheet-9RDZpWCf.js} +1 -1
- modoboa/frontend_dist/assets/VSpacer-BWZq1PhD.js +1 -0
- modoboa/frontend_dist/assets/{VSwitch-DwxdeAEq.js → VSwitch-CixaedmQ.js} +1 -1
- modoboa/frontend_dist/assets/{VTable-DaLxa4FO.js → VTable-DO7ofPSj.js} +1 -1
- modoboa/frontend_dist/assets/{VTabs-BP0Hgsgm.js → VTabs-C1-E1DJE.js} +1 -1
- modoboa/frontend_dist/assets/{VTextField-XoGTj1KG.js → VTextField-C9VUP7V9.js} +1 -1
- modoboa/frontend_dist/assets/{VTextarea-wBlRMIv_.js → VTextarea-B28SmJ2v.js} +1 -1
- modoboa/frontend_dist/assets/{VToolbar-CFZfqeOr.js → VToolbar-Cs-fVa4M.js} +1 -1
- modoboa/frontend_dist/assets/VWindowItem-C9PFEbE6.js +1 -0
- modoboa/frontend_dist/assets/WebmailLayout-Dp6jIazW.js +1 -0
- modoboa/frontend_dist/assets/{accounts-DUzbx6k8.js → accounts-BT429O7P.js} +1 -1
- modoboa/frontend_dist/assets/{admin-DewTk2H8.js → admin-Cu5rjY7m.js} +1 -1
- modoboa/frontend_dist/assets/{aliases-4sXmjwXp.js → aliases-Q4uTcEh4.js} +1 -1
- modoboa/frontend_dist/assets/{amavis-CC0li7_T.js → amavis-Be87kCqw.js} +1 -1
- modoboa/frontend_dist/assets/{amavis-DK8SHE6o.js → amavis-Bx0pxvRn.js} +1 -1
- modoboa/frontend_dist/assets/{contacts-BjghrPqZ.js → contacts-Dx240BT8.js} +1 -1
- modoboa/frontend_dist/assets/{domains-BSawReeu.js → domains-CQv8gtbQ.js} +1 -1
- modoboa/frontend_dist/assets/{domains.store-D-vWCEIK.js → domains.store-CfpnnBGo.js} +1 -1
- modoboa/frontend_dist/assets/{filter-C82FUCw_.js → filter-C_GJovn5.js} +1 -1
- modoboa/frontend_dist/assets/{forwardRefs-cvcnlhoK.js → forwardRefs-DPrLRqxP.js} +1 -1
- modoboa/frontend_dist/assets/{global.store-DbkcI5o2.js → global.store-CNChIxQL.js} +1 -1
- modoboa/frontend_dist/assets/importExport-7sRHU_3R.js +1 -0
- modoboa/frontend_dist/assets/index-YIGRKgNA.js +982 -0
- modoboa/frontend_dist/assets/{layout-C5FyYCHK.js → layout-BM4C5b2r.js} +1 -1
- modoboa/frontend_dist/assets/{layout.store-NXWtFIwL.js → layout.store-CCOp6tv6.js} +1 -1
- modoboa/frontend_dist/assets/{logos-BswdveCV.js → logos-CboXciB_.js} +1 -1
- modoboa/frontend_dist/assets/{logs-6CbtfaZS.js → logs-BeuijmJA.js} +1 -1
- modoboa/frontend_dist/assets/{parameters-aSQiR7kN.js → parameters-DpVw-Zs4.js} +1 -1
- modoboa/frontend_dist/assets/{parameters.store-CzQqVatx.js → parameters.store-DRarkO6b.js} +1 -1
- modoboa/frontend_dist/assets/{permissions-DNoefz-n.js → permissions-C33K6cJv.js} +1 -1
- modoboa/frontend_dist/assets/{ssrBoot-CKUX4kcb.js → ssrBoot-CpJ-7WlH.js} +1 -1
- modoboa/frontend_dist/assets/{tag-B_yWNNJD.js → tag-DV1_zOzl.js} +1 -1
- modoboa/frontend_dist/assets/theme-BGzdVPko.js +1 -0
- modoboa/frontend_dist/assets/transports-B9mWU1W8.js +1 -0
- modoboa/frontend_dist/assets/{webmail-CdU6CD9b.js → webmail-DRyN8JIK.js} +1 -1
- modoboa/frontend_dist/index.html +1 -1
- modoboa/static/css/offline.css +7 -20
- modoboa/templates/registration/base.html +18 -0
- modoboa/templates/registration/login.html +1 -1
- modoboa/urls.py +1 -0
- modoboa/webmail/lib/imaputils.py +2 -2
- {modoboa-2.5.0.dist-info → modoboa-2.6.0.dist-info}/METADATA +6 -6
- {modoboa-2.5.0.dist-info → modoboa-2.6.0.dist-info}/RECORD +155 -147
- {modoboa-2.5.0.dist-info → modoboa-2.6.0.dist-info}/licenses/LICENSE +1 -1
- modoboa/frontend_dist/assets/AccountLayout-DrN7vHsX.js +0 -1
- modoboa/frontend_dist/assets/AdminLayout-CTNhuwTw.js +0 -1
- modoboa/frontend_dist/assets/AlarmsView-DN_JIw9g.js +0 -1
- modoboa/frontend_dist/assets/AliasEditView-Cx9410JP.css +0 -1
- modoboa/frontend_dist/assets/AliasEditView-DjpPUTp9.js +0 -1
- modoboa/frontend_dist/assets/AliasRecipientForm-B1Y8wFdP.js +0 -1
- modoboa/frontend_dist/assets/ComposeEmailView-s3LMl3pO.js +0 -1
- modoboa/frontend_dist/assets/ConfirmDialog-DY_kUHLG.js +0 -1
- modoboa/frontend_dist/assets/ConnectedLayout-UWjiYBNw.js +0 -1
- modoboa/frontend_dist/assets/DashboardView-Dplk9itS.js +0 -1
- modoboa/frontend_dist/assets/EmptyLayout-DFfhnhLi.js +0 -1
- modoboa/frontend_dist/assets/ForwardEmailView-CZG062os.js +0 -1
- modoboa/frontend_dist/assets/LoginCallbackView-B9hAH4MI.js +0 -1
- modoboa/frontend_dist/assets/MailboxView-Bugu2vhg.js +0 -1
- modoboa/frontend_dist/assets/ParametersView-CX7Ffemw.js +0 -1
- modoboa/frontend_dist/assets/ParametersView-CrbNcmV3.js +0 -1
- modoboa/frontend_dist/assets/QuarantineLayout-B8EcU9vS.js +0 -1
- modoboa/frontend_dist/assets/ReplyEmailView-BABPqWhd.js +0 -1
- modoboa/frontend_dist/assets/ResourcesForm-OaqdRYVs.js +0 -1
- modoboa/frontend_dist/assets/SelfServiceLayout-d277YTGR.js +0 -1
- modoboa/frontend_dist/assets/UserLayout-B3sBiTcZ.js +0 -1
- modoboa/frontend_dist/assets/VColorPicker-BHscBGQV.js +0 -1
- modoboa/frontend_dist/assets/VSpacer-DinPiXs9.js +0 -1
- modoboa/frontend_dist/assets/VWindowItem-BB7ETW3b.js +0 -1
- modoboa/frontend_dist/assets/WebmailLayout-_Hk1XhVq.js +0 -1
- modoboa/frontend_dist/assets/importExport-DzoL4Mvc.js +0 -1
- modoboa/frontend_dist/assets/index-BImkz5Jx.js +0 -984
- modoboa/frontend_dist/assets/transports-BDNB9wR5.js +0 -1
- {modoboa-2.5.0.data → modoboa-2.6.0.data}/scripts/modoboa-admin.py +0 -0
- {modoboa-2.5.0.dist-info → modoboa-2.6.0.dist-info}/WHEEL +0 -0
- {modoboa-2.5.0.dist-info → modoboa-2.6.0.dist-info}/entry_points.txt +0 -0
- {modoboa-2.5.0.dist-info → modoboa-2.6.0.dist-info}/top_level.txt +0 -0
|
@@ -745,7 +745,7 @@ class CSVImportSerializer(serializers.Serializer):
|
|
|
745
745
|
class CSVIdentityImportSerializer(CSVImportSerializer):
|
|
746
746
|
"""Custom serializer for identity import."""
|
|
747
747
|
|
|
748
|
-
crypt_passwords = serializers.BooleanField()
|
|
748
|
+
crypt_passwords = serializers.BooleanField(default=False)
|
|
749
749
|
|
|
750
750
|
|
|
751
751
|
class AlarmSerializer(serializers.ModelSerializer):
|
modoboa/admin/models/domain.py
CHANGED
|
@@ -202,7 +202,7 @@ class Domain(mixins.MessageLimitMixin, AdminObject):
|
|
|
202
202
|
return self.dnsrecord_set.filter(type="autodiscover").first()
|
|
203
203
|
|
|
204
204
|
@cached_property
|
|
205
|
-
def allocated_quota(self):
|
|
205
|
+
def allocated_quota(self) -> int:
|
|
206
206
|
"""Return current quota allocation."""
|
|
207
207
|
if not self.quota:
|
|
208
208
|
return 0
|
modoboa/admin/models/mixins.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Admin model mixins."""
|
|
2
2
|
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
3
5
|
from modoboa.policyd.utils import get_message_counter
|
|
4
6
|
|
|
5
7
|
|
|
@@ -18,7 +20,7 @@ class MessageLimitMixin:
|
|
|
18
20
|
return self.message_limit - get_message_counter(self.message_counter_key)
|
|
19
21
|
|
|
20
22
|
@property
|
|
21
|
-
def sent_messages_in_percent(self):
|
|
23
|
+
def sent_messages_in_percent(self) -> Optional[int]: # noqa
|
|
22
24
|
"""Return number of sent messages as a percentage."""
|
|
23
25
|
if not self.message_limit:
|
|
24
26
|
return None
|
modoboa/amavis/serializers.py
CHANGED
|
@@ -10,7 +10,7 @@ from modoboa.amavis import models
|
|
|
10
10
|
class GlobalParametersSerializer(serializers.Serializer):
|
|
11
11
|
|
|
12
12
|
localpart_is_case_sensitive = serializers.BooleanField(default=False)
|
|
13
|
-
recipient_delimiter = serializers.CharField(default="")
|
|
13
|
+
recipient_delimiter = serializers.CharField(default="", allow_blank=True)
|
|
14
14
|
max_messages_age = serializers.IntegerField(default=14)
|
|
15
15
|
released_msgs_cleanup = serializers.BooleanField(default=False)
|
|
16
16
|
am_pdp_mode = serializers.ChoiceField(
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<clientConfig version="1.1">
|
|
3
|
+
<emailProvider id="{{ domain }}">
|
|
4
|
+
<domain>{{ domain }}</domain>
|
|
5
|
+
<displayName>Modoboa</displayName>
|
|
6
|
+
<displayShortName>Mail</displayShortName>
|
|
7
|
+
|
|
8
|
+
<incomingServer type="imap">
|
|
9
|
+
<hostname>{{ connection_settings.imap.HOSTNAME }}</hostname>
|
|
10
|
+
<port>{{ connection_settings.imap.PORT }}</port>
|
|
11
|
+
<socketType>{{ connection_settings.imap.SOCKET_TYPE }}</socketType>
|
|
12
|
+
<authentication>plain</authentication>
|
|
13
|
+
<username>{{ emailaddress }}</username>
|
|
14
|
+
</incomingServer>
|
|
15
|
+
|
|
16
|
+
<outgoingServer type="smtp">
|
|
17
|
+
<hostname>{{ connection_settings.smtp.HOSTNAME }}</hostname>
|
|
18
|
+
<port>{{ connection_settings.smtp.PORT }}</port>
|
|
19
|
+
<socketType>{{ connection_settings.smtp.SOCKET_TYPE }}</socketType>
|
|
20
|
+
<authentication>plain</authentication>
|
|
21
|
+
<username>{{ emailaddress }}</username>
|
|
22
|
+
</outgoingServer>
|
|
23
|
+
</emailProvider>
|
|
24
|
+
</clientConfig>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
|
|
3
|
+
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
|
|
4
|
+
<Account>
|
|
5
|
+
<AccountType>email</AccountType>
|
|
6
|
+
<Action>settings</Action>
|
|
7
|
+
|
|
8
|
+
<Protocol>
|
|
9
|
+
<Type>IMAP</Type>
|
|
10
|
+
<Server>{{ connection_settings.imap.HOSTNAME }}</Server>
|
|
11
|
+
<Port>{{ connection_settings.imap.PORT }}</Port>
|
|
12
|
+
<SSL>true</SSL>
|
|
13
|
+
<LoginName>{{ emailaddress }}</LoginName>
|
|
14
|
+
</Protocol>
|
|
15
|
+
|
|
16
|
+
<Protocol>
|
|
17
|
+
<Type>SMTP</Type>
|
|
18
|
+
<Server>{{ connection_settings.smtp.HOSTNAME }}</Server>
|
|
19
|
+
<Port>{{ connection_settings.smtp.PORT }}</Port>
|
|
20
|
+
<SSL>false</SSL>
|
|
21
|
+
<TLS>true</TLS>
|
|
22
|
+
<LoginName>{{ emailaddress }}</LoginName>
|
|
23
|
+
</Protocol>
|
|
24
|
+
|
|
25
|
+
</Account>
|
|
26
|
+
</Response>
|
|
27
|
+
</Autodiscover>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from django.test import TestCase
|
|
2
|
+
from django.urls import reverse
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ViewsTestCase(TestCase):
|
|
6
|
+
|
|
7
|
+
databases = "__all__"
|
|
8
|
+
|
|
9
|
+
def test_autoconfig(self):
|
|
10
|
+
url = reverse("autoconfig:autoconfig")
|
|
11
|
+
|
|
12
|
+
resp = self.client.get(url)
|
|
13
|
+
self.assertEqual(resp.status_code, 404)
|
|
14
|
+
|
|
15
|
+
resp = self.client.get(f"{url}?emailaddress=test@test.com")
|
|
16
|
+
self.assertEqual(resp.status_code, 200)
|
|
17
|
+
|
|
18
|
+
self.assertIn(b'<emailProvider id="test.com">', resp.content)
|
|
19
|
+
|
|
20
|
+
def test_autodiscover(self):
|
|
21
|
+
url = reverse("autoconfig:autodiscover")
|
|
22
|
+
|
|
23
|
+
resp = self.client.post(url)
|
|
24
|
+
self.assertEqual(resp.status_code, 404)
|
|
25
|
+
|
|
26
|
+
resp = self.client.post(url, {"EmailAddress": "test@test.com"})
|
|
27
|
+
self.assertEqual(resp.status_code, 200)
|
|
28
|
+
|
|
29
|
+
self.assertIn(b"<LoginName>test@test.com", resp.content)
|
|
30
|
+
|
|
31
|
+
def test_mobileconfig(self):
|
|
32
|
+
url = reverse("autoconfig:mobileconfig")
|
|
33
|
+
|
|
34
|
+
resp = self.client.get(url)
|
|
35
|
+
self.assertEqual(resp.status_code, 404)
|
|
36
|
+
|
|
37
|
+
resp = self.client.get(f"{url}?emailaddress=test@test.com")
|
|
38
|
+
self.assertEqual(resp.status_code, 200)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Autoconfig urls."""
|
|
2
|
+
|
|
3
|
+
from django.urls import path
|
|
4
|
+
|
|
5
|
+
from modoboa.autoconfig import views
|
|
6
|
+
|
|
7
|
+
app_name = "autoconfig"
|
|
8
|
+
|
|
9
|
+
urlpatterns = [
|
|
10
|
+
path(
|
|
11
|
+
"mail/config-v1.1.xml",
|
|
12
|
+
views.AutoConfigView.as_view(),
|
|
13
|
+
name="autoconfig",
|
|
14
|
+
),
|
|
15
|
+
path(
|
|
16
|
+
"autodiscover/autodiscover.xml",
|
|
17
|
+
views.AutoDiscoverView.as_view(),
|
|
18
|
+
name="autodiscover",
|
|
19
|
+
),
|
|
20
|
+
path("mobileconfig", views.MobileConfigView.as_view(), name="mobileconfig"),
|
|
21
|
+
]
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import plistlib
|
|
2
|
+
import uuid
|
|
3
|
+
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.http import Http404, HttpResponse
|
|
6
|
+
from django.utils.decorators import method_decorator
|
|
7
|
+
from django.views import generic
|
|
8
|
+
from django.views.decorators.csrf import csrf_exempt
|
|
9
|
+
|
|
10
|
+
from modoboa.lib.email_utils import split_address
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ConfigBaseMixin:
|
|
14
|
+
|
|
15
|
+
content_type = "application/xml"
|
|
16
|
+
|
|
17
|
+
def get_common_context(self, emailaddress: str) -> dict:
|
|
18
|
+
local_part, domain = split_address(emailaddress)
|
|
19
|
+
return {
|
|
20
|
+
"emailaddress": emailaddress,
|
|
21
|
+
"domain": domain,
|
|
22
|
+
"connection_settings": settings.EMAIL_CLIENT_CONNECTION_SETTINGS,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AutoConfigView(ConfigBaseMixin, generic.TemplateView):
|
|
27
|
+
|
|
28
|
+
http_method_names = ["get"]
|
|
29
|
+
template_name = "autoconfig/autoconfig.xml"
|
|
30
|
+
|
|
31
|
+
def get_context_data(self, **kwargs):
|
|
32
|
+
emailaddress = self.request.GET.get("emailaddress")
|
|
33
|
+
if not emailaddress:
|
|
34
|
+
raise Http404
|
|
35
|
+
context = super().get_context_data(**kwargs)
|
|
36
|
+
context.update(self.get_common_context(emailaddress))
|
|
37
|
+
return context
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@method_decorator(csrf_exempt, name="dispatch")
|
|
41
|
+
class AutoDiscoverView(ConfigBaseMixin, generic.TemplateView):
|
|
42
|
+
|
|
43
|
+
http_method_names = ["post"]
|
|
44
|
+
template_name = "autoconfig/autodiscover.xml"
|
|
45
|
+
|
|
46
|
+
def get_context_data(self, **kwargs):
|
|
47
|
+
emailaddress = self.request.POST.get("EmailAddress")
|
|
48
|
+
if not emailaddress:
|
|
49
|
+
raise Http404
|
|
50
|
+
context = super().get_context_data(**kwargs)
|
|
51
|
+
context.update(self.get_common_context(emailaddress))
|
|
52
|
+
return context
|
|
53
|
+
|
|
54
|
+
def post(self, request, *args, **kwargs):
|
|
55
|
+
context = self.get_context_data(**kwargs)
|
|
56
|
+
return self.render_to_response(context)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MobileConfigView(generic.View):
|
|
60
|
+
|
|
61
|
+
http_method_names = ["get"]
|
|
62
|
+
|
|
63
|
+
def get(self, request, *args, **kwargs):
|
|
64
|
+
emailaddress = self.request.GET.get("emailaddress")
|
|
65
|
+
if not emailaddress:
|
|
66
|
+
raise Http404
|
|
67
|
+
local_part, domain = split_address(emailaddress)
|
|
68
|
+
parts = domain.split(".")
|
|
69
|
+
parts.reverse()
|
|
70
|
+
reverse_domain = ".".join(parts)
|
|
71
|
+
imap_settings = settings.EMAIL_CLIENT_CONNECTION_SETTINGS["imap"]
|
|
72
|
+
smtp_settings = settings.EMAIL_CLIENT_CONNECTION_SETTINGS["smtp"]
|
|
73
|
+
profile = {
|
|
74
|
+
"PayloadType": "Configuration",
|
|
75
|
+
"PayloadVersion": 1,
|
|
76
|
+
"PayloadIdentifier": f"{reverse_domain}.mailprofile",
|
|
77
|
+
"PayloadUUID": str(uuid.uuid4()),
|
|
78
|
+
"PayloadDisplayName": f"{domain} Mail Configuration",
|
|
79
|
+
"PayloadOrganization": domain,
|
|
80
|
+
"PayloadContent": [
|
|
81
|
+
{
|
|
82
|
+
"PayloadType": "com.apple.mail.managed",
|
|
83
|
+
"PayloadVersion": 1,
|
|
84
|
+
"PayloadIdentifier": f"{reverse_domain}.mailprofile.mail",
|
|
85
|
+
"PayloadUUID": str(uuid.uuid4()),
|
|
86
|
+
"PayloadDisplayName": "Mail",
|
|
87
|
+
"EmailAccountDescription": f"{domain} Mail",
|
|
88
|
+
"EmailAccountType": "EmailTypeIMAP",
|
|
89
|
+
"EmailAddress": emailaddress,
|
|
90
|
+
# incoming
|
|
91
|
+
"IncomingMailServerHostName": imap_settings["HOSTNAME"],
|
|
92
|
+
"IncomingMailServerPortNumber": imap_settings["PORT"],
|
|
93
|
+
"IncomingMailServerUseSSL": True,
|
|
94
|
+
"IncomingMailServerUsername": emailaddress,
|
|
95
|
+
# outgoing
|
|
96
|
+
"OutgoingMailServerHostName": smtp_settings["HOSTNAME"],
|
|
97
|
+
"OutgoingMailServerPortNumber": smtp_settings["PORT"],
|
|
98
|
+
"OutgoingMailServerUseSSL": True,
|
|
99
|
+
"OutgoingMailServerUsername": emailaddress,
|
|
100
|
+
"OutgoingPasswordSameAsIncomingPassword": True,
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
}
|
|
104
|
+
plist_bytes = plistlib.dumps(profile, fmt=plistlib.FMT_XML)
|
|
105
|
+
resp = HttpResponse(
|
|
106
|
+
plist_bytes, content_type="application/x-apple-aspen-config"
|
|
107
|
+
)
|
|
108
|
+
resp["Content-Disposition"] = 'attachment; filename="mail.mobileconfig"'
|
|
109
|
+
return resp
|
|
@@ -62,7 +62,7 @@ class ARMessageViewSetTestCase(PatcherMixin, ModoAPITestCase):
|
|
|
62
62
|
def test_retrieve_armessage_domadmin(self):
|
|
63
63
|
admin = User.objects.get(username="admin@test.com")
|
|
64
64
|
self.client.logout()
|
|
65
|
-
self.client.
|
|
65
|
+
self.client.force_authenticate(admin)
|
|
66
66
|
url = reverse("api:armessage-list")
|
|
67
67
|
response = self.client.get(url)
|
|
68
68
|
self.assertEqual(response.status_code, 200)
|
|
@@ -74,7 +74,7 @@ class ARMessageViewSetTestCase(PatcherMixin, ModoAPITestCase):
|
|
|
74
74
|
|
|
75
75
|
def test_retrieve_armessage_simpleuser(self):
|
|
76
76
|
self.client.logout()
|
|
77
|
-
self.client.
|
|
77
|
+
self.client.force_authenticate(self.account)
|
|
78
78
|
url = reverse("api:armessage-list")
|
|
79
79
|
response = self.client.get(url)
|
|
80
80
|
self.assertEqual(response.status_code, 200)
|
|
@@ -156,7 +156,7 @@ class AccountARMessageViewSetTestCase(PatcherMixin, ModoAPITestCase):
|
|
|
156
156
|
response = self.client.get(url)
|
|
157
157
|
self.assertEqual(response.status_code, 403)
|
|
158
158
|
self.client.logout()
|
|
159
|
-
self.client.
|
|
159
|
+
self.client.force_authenticate(self.account)
|
|
160
160
|
self.assertFalse(
|
|
161
161
|
models.ARmessage.objects.filter(mbox=self.account.mailbox).exists()
|
|
162
162
|
)
|
|
@@ -168,7 +168,7 @@ class AccountARMessageViewSetTestCase(PatcherMixin, ModoAPITestCase):
|
|
|
168
168
|
|
|
169
169
|
def test_set_armessage(self):
|
|
170
170
|
self.client.logout()
|
|
171
|
-
self.client.
|
|
171
|
+
self.client.force_authenticate(self.account)
|
|
172
172
|
url = reverse("api:account_armessage-armessage")
|
|
173
173
|
fromdate = timezone.now()
|
|
174
174
|
todate = fromdate + relativedelta(days=4)
|
modoboa/calendars/tests.py
CHANGED
|
@@ -13,7 +13,7 @@ from modoboa.admin import factories as admin_factories
|
|
|
13
13
|
from modoboa.admin import models as admin_models
|
|
14
14
|
from modoboa.core import factories as core_factories
|
|
15
15
|
from modoboa.core import models as core_models
|
|
16
|
-
from modoboa.lib.tests import
|
|
16
|
+
from modoboa.lib.tests import ModoAPITestCase
|
|
17
17
|
|
|
18
18
|
from modoboa.admin.factories import populate_database
|
|
19
19
|
|
|
@@ -53,7 +53,7 @@ class TestDataMixin:
|
|
|
53
53
|
cls.scalendar2 = factories.SharedCalendarFactory(domain=cls.domain2)
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
class AccessRuleTestCase(
|
|
56
|
+
class AccessRuleTestCase(ModoAPITestCase):
|
|
57
57
|
|
|
58
58
|
@classmethod
|
|
59
59
|
def setUpTestData(cls):
|
|
@@ -139,7 +139,7 @@ class UserCalendarViewSetTestCase(TestDataMixin, ModoAPITestCase):
|
|
|
139
139
|
|
|
140
140
|
def setUp(self):
|
|
141
141
|
"""Initiate test context."""
|
|
142
|
-
self.client.
|
|
142
|
+
self.client.force_authenticate(self.account)
|
|
143
143
|
self.set_global_parameter("server_location", "http://localhost:5232")
|
|
144
144
|
|
|
145
145
|
def test_get_calendars(self):
|
|
@@ -214,7 +214,7 @@ class SharedCalendarViewSetTestCase(TestDataMixin, ModoAPITestCase):
|
|
|
214
214
|
|
|
215
215
|
def setUp(self):
|
|
216
216
|
"""Initiate test context."""
|
|
217
|
-
self.client.
|
|
217
|
+
self.client.force_authenticate(self.admin_account)
|
|
218
218
|
self.set_global_parameter("server_location", "http://localhost:5232")
|
|
219
219
|
|
|
220
220
|
def test_get_calendars(self):
|
|
@@ -304,7 +304,7 @@ class AccessRuleViewSetTestCase(TestDataMixin, ModoAPITestCase):
|
|
|
304
304
|
|
|
305
305
|
def setUp(self):
|
|
306
306
|
"""Initiate test context."""
|
|
307
|
-
self.client.
|
|
307
|
+
self.client.force_authenticate(self.account)
|
|
308
308
|
|
|
309
309
|
def test_get_accessrules(self):
|
|
310
310
|
"""Test access rule retrieval."""
|
|
@@ -383,7 +383,7 @@ class EventViewSetTestCase(TestDataMixin, ModoAPITestCase):
|
|
|
383
383
|
self.cal_mock.return_value = mocks.Calendar(client=self.client_mock)
|
|
384
384
|
self.addCleanup(patcher2.stop)
|
|
385
385
|
|
|
386
|
-
self.client.
|
|
386
|
+
self.client.force_authenticate(self.account)
|
|
387
387
|
self.set_global_parameter("server_location", "http://localhost")
|
|
388
388
|
|
|
389
389
|
def test_get_user_events(self):
|
|
@@ -550,7 +550,7 @@ class AttendeeViewSetTestCase(ModoAPITestCase):
|
|
|
550
550
|
|
|
551
551
|
def setUp(self):
|
|
552
552
|
"""Initiate test context."""
|
|
553
|
-
self.client.
|
|
553
|
+
self.client.force_authenticate(self.account)
|
|
554
554
|
|
|
555
555
|
def test_get_attendees(self):
|
|
556
556
|
"""Test attendees retrieval."""
|
|
@@ -571,7 +571,7 @@ class MailboxViewSetTestCase(ModoAPITestCase):
|
|
|
571
571
|
|
|
572
572
|
def setUp(self):
|
|
573
573
|
"""Initiate test context."""
|
|
574
|
-
self.client.
|
|
574
|
+
self.client.force_authenticate(self.account)
|
|
575
575
|
|
|
576
576
|
def test_get_mailboxes(self):
|
|
577
577
|
"""Test mailbox retrieval."""
|
modoboa/contacts/tests.py
CHANGED
|
@@ -11,7 +11,7 @@ from django.utils import timezone
|
|
|
11
11
|
|
|
12
12
|
from modoboa.admin import factories as admin_factories
|
|
13
13
|
from modoboa.core import models as core_models
|
|
14
|
-
from modoboa.lib.tests import ModoAPITestCase
|
|
14
|
+
from modoboa.lib.tests import ModoAPITestCase
|
|
15
15
|
|
|
16
16
|
from . import factories
|
|
17
17
|
from . import mocks
|
|
@@ -46,7 +46,7 @@ class TestDataMixin:
|
|
|
46
46
|
|
|
47
47
|
def setUp(self, *args, **kwargs):
|
|
48
48
|
"""Initiate test context."""
|
|
49
|
-
self.client.
|
|
49
|
+
self.client.force_authenticate(self.user)
|
|
50
50
|
self.set_global_parameter(
|
|
51
51
|
"server_location", "http://example.test/radicale/", app="calendars"
|
|
52
52
|
)
|
|
@@ -72,8 +72,7 @@ class ViewsTestCase(TestDataMixin, ModoAPITestCase):
|
|
|
72
72
|
def test_user_settings(self):
|
|
73
73
|
"""Check that remote collection creation request is sent."""
|
|
74
74
|
# 1. Addressbook with contacts must be synced manually
|
|
75
|
-
|
|
76
|
-
self.client.post(reverse("core:login"), data)
|
|
75
|
+
self.client.force_authenticate(self.user)
|
|
77
76
|
self.enable_cdav_sync()
|
|
78
77
|
self.addressbook.refresh_from_db()
|
|
79
78
|
self.assertIs(self.addressbook.last_sync, None)
|
|
@@ -81,8 +80,7 @@ class ViewsTestCase(TestDataMixin, ModoAPITestCase):
|
|
|
81
80
|
# 2. Addressbook with no contacts can be considered synced
|
|
82
81
|
user = core_models.User.objects.get(username="user@test2.com")
|
|
83
82
|
abook = user.addressbook_set.first()
|
|
84
|
-
|
|
85
|
-
self.client.post(reverse("core:login"), data)
|
|
83
|
+
self.client.force_authenticate(user)
|
|
86
84
|
abook.refresh_from_db()
|
|
87
85
|
self.assertIs(abook.last_sync, None)
|
|
88
86
|
# Now enable sync.
|
|
@@ -312,7 +310,7 @@ class EmailAddressViewSetTestCase(TestDataMixin, ModoAPITestCase):
|
|
|
312
310
|
self.assertEqual(len(response.data), 3)
|
|
313
311
|
|
|
314
312
|
|
|
315
|
-
class ImportTestCase(TestDataMixin,
|
|
313
|
+
class ImportTestCase(TestDataMixin, ModoAPITestCase):
|
|
316
314
|
|
|
317
315
|
def setUp(self):
|
|
318
316
|
super().setUp()
|
modoboa/core/api/v1/tests.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from django.urls import reverse_lazy
|
|
2
2
|
|
|
3
|
-
from modoboa.lib.tests import
|
|
3
|
+
from modoboa.lib.tests import ModoAPITestCase
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
class OpenAPITestCase(
|
|
6
|
+
class OpenAPITestCase(ModoAPITestCase):
|
|
7
7
|
openapi_schema_url = reverse_lazy("schema-v1-legacy")
|
|
8
8
|
|
|
9
9
|
def test_unauthorized(self):
|
modoboa/core/api/v2/views.py
CHANGED
|
@@ -157,7 +157,9 @@ class ComponentsInformationAPIView(APIView):
|
|
|
157
157
|
class NotificationsAPIView(APIView):
|
|
158
158
|
"""Return list of active notifications."""
|
|
159
159
|
|
|
160
|
-
permission_classes = [
|
|
160
|
+
permission_classes = [
|
|
161
|
+
permissions.IsAuthenticated,
|
|
162
|
+
]
|
|
161
163
|
throttle_classes = [UserLesserDdosUser]
|
|
162
164
|
|
|
163
165
|
@extend_schema(responses=serializers.NotificationSerializer(many=True))
|
modoboa/core/commands/deploy.py
CHANGED
|
@@ -218,6 +218,7 @@ class DeployCommand(Command):
|
|
|
218
218
|
allowed_host = "localhost"
|
|
219
219
|
extra_settings = []
|
|
220
220
|
extensions = parsed_args.extensions
|
|
221
|
+
amavis_enabled = False
|
|
221
222
|
if extensions:
|
|
222
223
|
if "all" in extensions:
|
|
223
224
|
extensions = self._get_extension_list()
|
|
@@ -233,6 +234,7 @@ class DeployCommand(Command):
|
|
|
233
234
|
exec_cmd(cmd, capture_output=False)
|
|
234
235
|
extra_settings = self.find_extra_settings(extensions)
|
|
235
236
|
extensions = [extension[1] for extension in extensions]
|
|
237
|
+
amavis_enabled = "modoboa.amavis" in extensions
|
|
236
238
|
|
|
237
239
|
mod = __import__(parsed_args.name, globals(), locals(), [smart_str("settings")])
|
|
238
240
|
tpl = self._render_template(
|
|
@@ -247,6 +249,7 @@ class DeployCommand(Command):
|
|
|
247
249
|
"devmode": parsed_args.devel,
|
|
248
250
|
"extensions": extensions,
|
|
249
251
|
"extra_settings": extra_settings,
|
|
252
|
+
"amavis_enabled": amavis_enabled,
|
|
250
253
|
},
|
|
251
254
|
)
|
|
252
255
|
with open(f"{path}/settings.py", "w") as fp:
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
Django settings for {{ name }} project.
|
|
3
3
|
|
|
4
4
|
For more information on this file, see
|
|
5
|
-
https://docs.djangoproject.com/en/
|
|
5
|
+
https://docs.djangoproject.com/en/dev/topics/settings/
|
|
6
6
|
|
|
7
7
|
For the full list of settings and their values, see
|
|
8
|
-
https://docs.djangoproject.com/en/
|
|
8
|
+
https://docs.djangoproject.com/en/dev/ref/settings/
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from logging.handlers import SysLogHandler
|
|
@@ -17,9 +17,6 @@ env = environ.Env()
|
|
|
17
17
|
BASE_DIR = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
|
|
18
18
|
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
|
|
19
19
|
|
|
20
|
-
# Quick-start development settings - unsuitable for production
|
|
21
|
-
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
|
22
|
-
|
|
23
20
|
# SECURITY WARNING: keep the secret key used in production secret!
|
|
24
21
|
SECRET_KEY = '{{ secret_key }}'
|
|
25
22
|
|
|
@@ -41,6 +38,19 @@ SITE_ID = 1
|
|
|
41
38
|
# The email address that error messages come from, such as those sent to ADMINS
|
|
42
39
|
#SERVER_EMAIL = 'webmaster@example.net'
|
|
43
40
|
|
|
41
|
+
EMAIL_CLIENT_CONNECTION_SETTINGS = {
|
|
42
|
+
'imap': {
|
|
43
|
+
'HOSTNAME': '{{ allowed_host }}',
|
|
44
|
+
'SOCKET_TYPE': 'SSL',
|
|
45
|
+
'PORT': 993,
|
|
46
|
+
},
|
|
47
|
+
'smtp': {
|
|
48
|
+
'HOSTNAME': '{{ allowed_host }}',
|
|
49
|
+
'SOCKET_TYPE': 'STARTTLS',
|
|
50
|
+
'PORT': 587
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
44
54
|
# Security settings
|
|
45
55
|
|
|
46
56
|
X_FRAME_OPTIONS = "SAMEORIGIN"
|
|
@@ -78,6 +88,7 @@ MODOBOA_APPS = (
|
|
|
78
88
|
'modoboa.core',
|
|
79
89
|
'modoboa.lib',
|
|
80
90
|
'modoboa.admin',
|
|
91
|
+
'modoboa.autoconfig',
|
|
81
92
|
'modoboa.transport',
|
|
82
93
|
'modoboa.relaydomains',
|
|
83
94
|
'modoboa.limits',
|
|
@@ -157,14 +168,14 @@ WSGI_APPLICATION = '{{ name }}.wsgi.application'
|
|
|
157
168
|
|
|
158
169
|
|
|
159
170
|
# Database
|
|
160
|
-
# https://docs.djangoproject.com/en/
|
|
171
|
+
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
|
|
161
172
|
|
|
162
173
|
DATABASES = {
|
|
163
174
|
{% for conn in db_connections.values %}{{ conn|safe }}{% endfor %}
|
|
164
175
|
}
|
|
165
176
|
|
|
166
177
|
# Internationalization
|
|
167
|
-
# https://docs.djangoproject.com/en/
|
|
178
|
+
# https://docs.djangoproject.com/en/dev/topics/i18n/
|
|
168
179
|
|
|
169
180
|
LANGUAGE_CODE = '{{ lang }}'
|
|
170
181
|
|
|
@@ -177,12 +188,12 @@ USE_L10N = True
|
|
|
177
188
|
USE_TZ = True
|
|
178
189
|
|
|
179
190
|
# Default primary key field type
|
|
180
|
-
# https://docs.djangoproject.com/en/
|
|
191
|
+
# https://docs.djangoproject.com/en/dev/ref/settings/#default-auto-field
|
|
181
192
|
|
|
182
193
|
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
|
183
194
|
|
|
184
195
|
# Static files (CSS, JavaScript, Images)
|
|
185
|
-
# https://docs.djangoproject.com/en/
|
|
196
|
+
# https://docs.djangoproject.com/en/dev/howto/static-files/
|
|
186
197
|
|
|
187
198
|
STATIC_URL = '/sitestatic/'
|
|
188
199
|
STATIC_ROOT = os.path.join(BASE_DIR, 'sitestatic')
|
|
@@ -224,7 +235,6 @@ REST_FRAMEWORK = {
|
|
|
224
235
|
'DEFAULT_AUTHENTICATION_CLASSES': (
|
|
225
236
|
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
|
|
226
237
|
'rest_framework.authentication.TokenAuthentication',
|
|
227
|
-
'rest_framework.authentication.SessionAuthentication',
|
|
228
238
|
),
|
|
229
239
|
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
|
230
240
|
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning',
|
|
@@ -295,7 +305,7 @@ CACHES = {
|
|
|
295
305
|
|
|
296
306
|
|
|
297
307
|
# Password validation
|
|
298
|
-
# https://docs.djangoproject.com/en/
|
|
308
|
+
# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators
|
|
299
309
|
|
|
300
310
|
AUTH_PASSWORD_VALIDATORS = [
|
|
301
311
|
{
|
|
@@ -384,7 +394,11 @@ SILENCED_SYSTEM_CHECKS = [
|
|
|
384
394
|
]
|
|
385
395
|
|
|
386
396
|
PHONENUMBER_DB_FORMAT = 'INTERNATIONAL'
|
|
387
|
-
|
|
397
|
+
{% if amavis_enabled %}
|
|
398
|
+
# Amavis settings
|
|
399
|
+
DATABASE_ROUTERS = ["modoboa.amavis.dbrouter.AmavisRouter"]
|
|
400
|
+
AMAVIS_DEFAULT_DATABASE_ENCODING = "LATIN1" # or any value matching your database config
|
|
401
|
+
{% endif %}
|
|
388
402
|
# Load settings from extensions
|
|
389
403
|
{% for extension in extra_settings %}
|
|
390
404
|
try:
|
modoboa/core/models.py
CHANGED
modoboa/core/tests/test_ldap.py
CHANGED
|
@@ -158,6 +158,8 @@ class ProfileTestCase(LDAPTestCaseMixin, ModoAPITestCase):
|
|
|
158
158
|
|
|
159
159
|
username = "testuser@example.com"
|
|
160
160
|
self.authenticate(username, "test")
|
|
161
|
+
user = models.User.objects.get(username=username)
|
|
162
|
+
self.client.force_authenticate(user)
|
|
161
163
|
response = self.client.post(
|
|
162
164
|
reverse("v2:account-set-me-password"),
|
|
163
165
|
{"password": "test", "new_password": "Toto1234"},
|