merge from master

This commit is contained in:
Spitap
2023-02-23 20:51:43 +01:00
159 changed files with 53907 additions and 11133 deletions
+10 -2
View File
@@ -6,8 +6,16 @@ name: Modoboa App
on:
push:
branches: [ master ]
paths-ignore:
- 'modoboa/**.po'
- 'frontend/**'
- 'doc/**'
pull_request:
branches: [ master ]
paths-ignore:
- 'modoboa/**.po'
- 'frontend/**'
- 'doc/**'
release:
branches: [ master ]
types: [ published ]
@@ -93,7 +101,7 @@ jobs:
run: |
python ./tests.py
cd test_project
python3 manage.py test modoboa.core modoboa.lib modoboa.admin modoboa.limits modoboa.transport modoboa.relaydomains modoboa.dnstools modoboa.ldapsync modoboa.policyd modoboa.maillog modoboa.parameters
python3 manage.py test modoboa.core modoboa.lib modoboa.admin modoboa.limits modoboa.transport modoboa.relaydomains modoboa.dnstools modoboa.ldapsync modoboa.policyd modoboa.maillog modoboa.parameters modoboa.dmarc
env:
# use localhost for the host here because we are running the job on the VM.
# If we were running the job on in a container this would be postgres
@@ -109,7 +117,7 @@ jobs:
run: |
python ./tests.py
cd test_project
coverage run manage.py test modoboa.core modoboa.lib modoboa.admin modoboa.limits modoboa.transport modoboa.relaydomains modoboa.dnstools modoboa.ldapsync modoboa.policyd modoboa.maillog modoboa.parameters
coverage run manage.py test modoboa.core modoboa.lib modoboa.admin modoboa.limits modoboa.transport modoboa.relaydomains modoboa.dnstools modoboa.ldapsync modoboa.policyd modoboa.maillog modoboa.parameters modoboa.dmarc
coverage combine
env:
# use localhost for the host here because we are running the job on the VM.
+12 -4
View File
@@ -1,13 +1,13 @@
queue_rules:
- name: default
conditions:
- check-success=test (postgres, 3.7)
- check-success=test (postgres, 3.9)
pull_request_rules:
- name: automatic merge on CI success and review
conditions:
- check-success=test (postgres, 3.7)
- check-success=test (postgres, 3.9)
- "#approved-reviews-by>=1"
- "#review-requested=0"
- "#changes-requested-reviews-by=0"
@@ -24,7 +24,7 @@ pull_request_rules:
- name: automatic merge for pyUp pull requests
conditions:
- author=pyup-bot
- check-success=test (postgres, 3.7)
- check-success=test (postgres, 3.9)
- label=dependencies
- "#approved-reviews-by>=1"
actions:
@@ -34,10 +34,18 @@ pull_request_rules:
- name: automatic merge for dependabot pull requests
conditions:
- author~=^dependabot(|-preview)\[bot\]$
- check-success=test (postgres, 3.7)
- check-success=test (postgres, 3.9)
- label=dependencies
- "#approved-reviews-by>=1"
actions:
queue:
method: squash
name: default
- name: automatic merge for transifex pull requests
conditions:
- author~=^transifex-integration\[bot\]$
- "#approved-reviews-by>=1"
actions:
queue:
method: squash
name: default
+37 -4
View File
@@ -66,7 +66,7 @@ New admin interface won't update by itself. Run the following commands to update
> rm -rf frontend
> cp -R <virtuenv_path>/lib/pythonX.X/site-packages/modoboa/frontend_dist/ frontend/
> cp ./config.json frontend/config.json
Extensions
**********
@@ -108,7 +108,40 @@ Rebuild Virtual Environment
Specific instructions
*********************
2.0.4
2.1.0
=====
The ``modoboa-dmarc`` plugin has been merged into the core.
Add ``'modoboa.dmarc'`` to ``MODOBOA_APPS``:
.. sourcecode:: python
MODOBOA_APPS = (
'modoboa',
'modoboa.core',
'modoboa.lib',
'modoboa.admin',
'modoboa.transport',
'modoboa.relaydomains',
'modoboa.limits',
'modoboa.parameters',
'modoboa.dnstools',
'modoboa.policyd',
'modoboa.maillog',
'modoboa.dmarc',
)
And remove any reference to ``modoboa_dmarc`` in this same variable.
FIXME: INSTALLATION django-rename-app
.. sourcecode:: bash
python manage.py rename_app modoboa_dmarc dmarc
2.0.4t
=====
The following modifications must be applied to the :file:`settings.py` file:
@@ -159,7 +192,7 @@ The following modifications must be applied to the :file:`settings.py` file:
},
* You now have the possibility to customize the url of the new-admin interface.
* You now have the possibility to customize the url of the new-admin interface.
To do so please head up to :ref:`the custom configuration chapter <customization>` (advanced user).
* Add ``DEFAULT_THROTTLE_RATES`` to ``REST_FRAMEWORK``:
@@ -187,7 +220,7 @@ The following modifications must be applied to the :file:`settings.py` file:
* You can edit the ``DEFAULT_THROTTLE_RATES`` to whatever value suits you.
- `user` is for every endpoint, it is per user or per ip if not logged.
- `ddos` is per api endpoint and per user or per ip if not logged.
- `ddos` is per api endpoint and per user or per ip if not logged.
- `ddos_lesser` is for per api endpoint and per user or per ip if not logged. This is for api endpoint that are lighter.
- `login` the number of time an ip can attempt to log. The counter will reset on login success.
- `password_` is for the recovery, it is divided per step in the recovery process.
+1 -1
View File
@@ -8,7 +8,7 @@ INPUT_DIR = src
OUTPUT_DIR = .
# Available locales for the app.
LOCALES = en fr
LOCALES = br cs de el es en fi fr it ja nl pt pt-br pl po ru sv tr zh-hant
# Name of the generated .po files for each available locale.
LOCALE_FILES ?= $(patsubst %,$(OUTPUT_DIR)/locale/%/LC_MESSAGES/app.po,$(LOCALES))
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+261 -41
View File
@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-27 16:52+0200\n"
"POT-Creation-Date: 2023-02-23 18:08+0100\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: en\n"
@@ -177,7 +177,11 @@ msgstr ""
msgid "Aliases"
msgstr ""
#: src/components/layout/Navbar.vue:93 src/components/layout/Navbar.vue:208
#: src/components/dmarc/DmarcAligmentChart.vue:4
msgid "Alignment"
msgstr ""
#: src/components/layout/Navbar.vue:99 src/components/layout/Navbar.vue:214
msgid "API"
msgstr ""
@@ -244,6 +248,11 @@ msgstr ""
msgid "Bind/named format. Click to copy"
msgstr ""
#: src/views/user/PasswordRecoveryForm.vue:26
#: src/views/user/PasswordRecoverySmsTotpForm.vue:19
msgid "body"
msgstr ""
#: src/components/domains/DomainForm.vue:122
#: src/components/identities/AccountForm.vue:94
#: src/components/identities/AliasForm.vue:55
@@ -252,6 +261,14 @@ msgstr ""
msgid "Cancel"
msgstr ""
#: src/views/user/PasswordRecoveryChangeForm.vue:10
msgid "Change password"
msgstr ""
#: src/components/admin/ComponentsInformationTable.vue:8
msgid "Check out the following list to find related components"
msgstr ""
#: src/views/identities/Identities.vue:45 src/views/identities/Identities.vue:1
msgid "Check this option if passwords contained in your file are not crypted"
msgstr ""
@@ -274,6 +291,10 @@ msgstr ""
msgid "Close"
msgstr ""
#: src/components/alarms/AlarmList.vue:21 src/components/alarms/AlarmList.vue:5
msgid "Closed"
msgstr ""
#: src/components/tools/CreationForm.vue:40
msgid "Confirm and create"
msgstr ""
@@ -288,7 +309,7 @@ msgstr ""
msgid "Congratulations! Two-Factor Authentication is now enabled for your account."
msgstr ""
#: src/views/Login.vue:21
#: src/views/Login.vue:23
msgid "Connect"
msgstr ""
@@ -363,16 +384,15 @@ msgstr ""
msgid "Dashboard"
msgstr ""
#: src/components/alarms/AlarmList.vue:8
#: src/components/logs/AuditTrailList.vue:8
#: src/components/logs/MessageList.vue:9 src/components/alarms/AlarmList.vue:48
#: src/components/logs/MessageList.vue:10
#: src/components/logs/AuditTrailList.vue:40
#: src/components/logs/MessageList.vue:42
#: src/components/logs/MessageList.vue:43
msgid "Date"
msgstr ""
#: src/components/tools/TimeSerieChart.vue:51
#: src/components/tools/TimeSerieChart.vue:109
#: src/components/tools/TimeSerieChart.vue:50
#: src/components/tools/TimeSerieChart.vue:108
msgid "Day"
msgstr ""
@@ -401,14 +421,20 @@ msgstr ""
msgid "Delete token"
msgstr ""
#: src/components/admin/ComponentsInformationTable.vue:16
#: src/components/identities/AliasCreationForm.vue:31
#: src/components/identities/AliasGeneralForm.vue:87
#: src/components/identities/AliasSummary.vue:19
#: src/components/identities/AliasCreationForm.vue:51
#: src/components/identities/AliasGeneralForm.vue:56
#: src/components/admin/ComponentsInformationTable.vue:54
msgid "Description"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:37
msgid "Detail"
msgstr ""
#: src/components/user/TwoFactorAuthForm.vue:57
#: src/components/user/TwoFactorAuthForm.vue:5
msgid "Disable 2FA"
@@ -459,6 +485,10 @@ msgstr ""
msgid "DKIM signing"
msgstr ""
#: src/views/domains/Domain.vue:17
msgid "DMARC"
msgstr ""
#: src/components/domains/DNSDetail.vue:79
#: src/components/domains/DNSDetail.vue:43
msgid "DMARC record found"
@@ -469,6 +499,10 @@ msgstr ""
msgid "DMARC record not found"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:50
msgid "DMARC support does not seem to be enabled for this domain."
msgstr ""
#: src/components/domains/DomainCreationForm.vue:31
#: src/components/domains/DomainCreationForm.vue:109
#: src/components/domains/DomainCreationForm.vue:115
@@ -509,11 +543,11 @@ msgstr ""
msgid "Do you really want to delete the alias %{ alias }?"
msgstr ""
#: src/components/alarms/AlarmList.vue:9
#: src/components/alarms/AlarmList.vue:10
#: src/components/identities/AliasGeneralForm.vue:56
#: src/views/domains/Domain.vue:3 src/views/domains/Domains.vue:20
#: src/components/identities/AliasGeneralForm.vue:31
#: src/components/alarms/AlarmList.vue:49
#: src/components/alarms/AlarmList.vue:74
msgid "Domain"
msgstr ""
@@ -601,6 +635,10 @@ msgstr ""
msgid "Edit domain alias"
msgstr ""
#: src/views/user/PasswordRecoveryChangeForm.vue:59
msgid "element"
msgstr ""
#: src/components/identities/AccountCreationForm.vue:48
#: src/components/identities/AccountCreationForm.vue:98
msgid "Email"
@@ -659,6 +697,20 @@ msgstr ""
msgid "Enter the code from the two-factor app on your mobile device. If you have lost your device, you may enter one of your recovery codes."
msgstr ""
#: src/views/user/PasswordRecoverySmsTotpForm.vue:11
msgid "Enter the code you've just received by SMS"
msgstr ""
#: src/views/user/PasswordRecoveryForm.vue:62
#: src/views/user/PasswordRecoverySmsTotpForm.vue:73
msgid "err"
msgstr ""
#: src/views/user/PasswordRecoverySmsTotpForm.vue:18
#: src/views/user/PasswordRecoverySmsTotpForm.vue:66
msgid "Error"
msgstr ""
#: src/components/identities/AccountMailboxForm.vue:5
msgid "Ex: 10MB. Leave empty for no limit"
msgstr ""
@@ -679,6 +731,13 @@ msgstr ""
msgid "Export domains and aliases to CSV"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:25
#: src/components/dmarc/DmarcAligmentChart.vue:37
#: src/components/dmarc/DmarcAligmentChart.vue:143
#: src/components/dmarc/DmarcAligmentChart.vue:155
msgid "Failed"
msgstr ""
#: src/components/identities/AccountCreationForm.vue:30
#: src/components/identities/AccountGeneralForm.vue:32
#: src/components/user/ProfileForm.vue:45
@@ -688,12 +747,13 @@ msgstr ""
msgid "First name"
msgstr ""
#: src/views/Login.vue:16
#: src/views/Login.vue:17 src/views/user/PasswordRecoveryChangeForm.vue:6
#: src/views/user/PasswordRecoveryForm.vue:6
msgid "Forgot password?"
msgstr ""
#: src/components/layout/Navbar.vue:117 src/views/user/Forward.vue:3
#: src/components/layout/Navbar.vue:232
#: src/components/layout/Navbar.vue:123 src/views/user/Forward.vue:3
#: src/components/layout/Navbar.vue:238
msgid "Forward"
msgstr ""
@@ -706,9 +766,20 @@ msgstr ""
msgid "Forward updated"
msgstr ""
#: src/components/logs/MessageList.vue:12
#: src/components/dmarc/DmarcAligmentChart.vue:24
#: src/components/dmarc/DmarcAligmentChart.vue:36
#: src/components/dmarc/DmarcAligmentChart.vue:142
#: src/components/dmarc/DmarcAligmentChart.vue:154
msgid "Forwarded"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:42
msgid "Forwarders with ARC"
msgstr ""
#: src/components/logs/MessageList.vue:13
#: src/components/tools/TimeSerieChart.vue:17
#: src/components/logs/MessageList.vue:45
#: src/components/logs/MessageList.vue:46
msgid "From"
msgstr ""
@@ -721,13 +792,20 @@ msgstr ""
msgid "Fullname/recipient"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:22
#: src/components/dmarc/DmarcAligmentChart.vue:34
#: src/components/dmarc/DmarcAligmentChart.vue:140
#: src/components/dmarc/DmarcAligmentChart.vue:152
msgid "Fully aligned"
msgstr ""
#: src/components/domains/DomainCreationForm.vue:23
#: src/components/domains/DomainCreationForm.vue:108
#: src/components/domains/DomainCreationForm.vue:114
#: src/components/domains/DomainForm.vue:7
#: src/components/identities/AliasCreationForm.vue:17
#: src/components/identities/AliasCreationForm.vue:49
#: src/components/identities/AliasForm.vue:7
#: src/components/identities/AliasForm.vue:7 src/views/domains/Domain.vue:11
#: src/components/identities/AliasCreationForm.vue:37
#: src/components/identities/AliasCreationForm.vue:69
#: src/components/domains/DomainCreationForm.vue:74
@@ -791,6 +869,10 @@ msgstr ""
msgid "If you close this form now, your modifications won't be saved. Do you confirm?"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:52
msgid "If you configured it recently, please wait for the first report to be received and processed."
msgstr ""
#: src/components/tools/ImportForm.vue:29
msgid "Import"
msgstr ""
@@ -815,6 +897,11 @@ msgstr ""
msgid "Indicate one or more recipients separated by a comma (,)"
msgstr ""
#: src/components/layout/Navbar.vue:92 src/views/admin/Information.vue:3
#: src/components/layout/Navbar.vue:207
msgid "Information"
msgstr ""
#: src/components/user/TwoFactorAuthForm.vue:14
#: src/components/user/TwoFactorAuthForm.vue:7
msgid ""
@@ -823,7 +910,21 @@ msgid ""
" app to scan this QR code."
msgstr ""
#: src/views/Login.vue:35 src/views/Login.vue:93
#: src/components/admin/ComponentsInformationTable.vue:3
msgid "Installed components"
msgstr ""
#: src/components/admin/ComponentsInformationTable.vue:14
#: src/components/admin/ComponentsInformationTable.vue:52
msgid "Installed version"
msgstr ""
#: src/views/user/PasswordRecoveryChangeForm.vue:54
#: src/views/user/PasswordRecoveryChangeForm.vue:114
msgid "Invalid reset token."
msgstr ""
#: src/views/Login.vue:35 src/views/Login.vue:95
msgid "Invalid username and/or password"
msgstr ""
@@ -863,6 +964,11 @@ msgstr ""
msgid "Last name"
msgstr ""
#: src/components/admin/ComponentsInformationTable.vue:15
#: src/components/admin/ComponentsInformationTable.vue:53
msgid "Latest version"
msgstr ""
#: src/components/identities/AccountMailboxForm.vue:8
msgid "Leave empty for no limit"
msgstr ""
@@ -887,8 +993,8 @@ msgstr ""
msgid "Logger"
msgstr ""
#: src/components/layout/Navbar.vue:133 src/components/layout/Topbar.vue:6
#: src/components/layout/Navbar.vue:248 src/components/layout/Topbar.vue:53
#: src/components/layout/Navbar.vue:139 src/components/layout/Topbar.vue:6
#: src/components/layout/Navbar.vue:254 src/components/layout/Topbar.vue:53
msgid "Logout"
msgstr ""
@@ -896,13 +1002,13 @@ msgstr ""
msgid "Logs"
msgstr ""
#: src/components/alarms/AlarmList.vue:10
#: src/components/alarms/AlarmList.vue:11
#: src/components/identities/AccountCreationForm.vue:46
#: src/components/identities/AccountCreationForm.vue:89
#: src/components/identities/AccountForm.vue:56
#: src/components/identities/AccountCreationForm.vue:96
#: src/components/identities/AccountCreationForm.vue:139
#: src/components/alarms/AlarmList.vue:50
#: src/components/alarms/AlarmList.vue:75
msgid "Mailbox"
msgstr ""
@@ -910,9 +1016,9 @@ msgstr ""
msgid "Mailboxes"
msgstr ""
#: src/components/alarms/AlarmList.vue:11
#: src/components/alarms/AlarmList.vue:12
#: src/components/logs/AuditTrailList.vue:11
#: src/components/alarms/AlarmList.vue:51
#: src/components/alarms/AlarmList.vue:76
#: src/components/logs/AuditTrailList.vue:43
msgid "Message"
msgstr ""
@@ -945,8 +1051,8 @@ msgstr ""
msgid "Modify"
msgstr ""
#: src/components/tools/TimeSerieChart.vue:53
#: src/components/tools/TimeSerieChart.vue:111
#: src/components/tools/TimeSerieChart.vue:52
#: src/components/tools/TimeSerieChart.vue:110
msgid "Month"
msgstr ""
@@ -954,6 +1060,7 @@ msgstr ""
msgid "MX records"
msgstr ""
#: src/components/admin/ComponentsInformationTable.vue:13
#: src/components/domains/AdministratorList.vue:19
#: src/components/domains/DNSDetail.vue:18
#: src/components/domains/DomainAliasForm.vue:40
@@ -967,6 +1074,7 @@ msgstr ""
#: src/components/domains/DomainCreationForm.vue:76
#: src/components/domains/AdministratorList.vue:87
#: src/components/domains/DomainList.vue:166
#: src/components/admin/ComponentsInformationTable.vue:51
msgid "Name"
msgstr ""
@@ -1041,11 +1149,24 @@ msgstr ""
msgid "Number of messages this mailbox can send per day. Leave empty for no limit."
msgstr ""
#: src/views/user/PasswordRecoveryForm.vue:31
#: src/views/user/PasswordRecoveryForm.vue:77
msgid "Ok"
msgstr ""
#: src/components/layout/ConfirmDialog.vue:15
#: src/components/layout/ConfirmDialog.vue:54
msgid "OK"
msgstr ""
#: src/components/admin/ComponentsInformationTable.vue:7
msgid "One or more updates are available"
msgstr ""
#: src/components/alarms/AlarmList.vue:18 src/components/alarms/AlarmList.vue:2
msgid "Opened"
msgstr ""
#: src/views/alarms/Alarms.vue:3
msgid "Opened alarms"
msgstr ""
@@ -1062,6 +1183,17 @@ msgstr ""
msgid "Parameters updated"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:23
#: src/components/dmarc/DmarcAligmentChart.vue:35
#: src/components/dmarc/DmarcAligmentChart.vue:141
#: src/components/dmarc/DmarcAligmentChart.vue:153
msgid "Partially aligned"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:41
msgid "Partially trusted sources / Forwarders"
msgstr ""
#: src/components/identities/AccountPasswordForm.vue:88
#: src/components/user/ProfileForm.vue:21 src/views/Login.vue:13
#: src/components/identities/AccountPasswordForm.vue:42
@@ -1077,6 +1209,10 @@ msgstr ""
msgid "Password copied to clipboard"
msgstr ""
#: src/views/user/PasswordRecoverySmsTotpForm.vue:8
msgid "Password recovery"
msgstr ""
#: src/components/user/ProfileForm.vue:42
#: src/components/user/ProfileForm.vue:112
msgid "Password updated"
@@ -1107,6 +1243,10 @@ msgstr ""
msgid "Pin code"
msgstr ""
#: src/views/user/PasswordRecoveryForm.vue:9
msgid "Please fill-in your primary email address"
msgstr ""
#: src/components/domains/DNSStatusChip.vue:12
#: src/components/domains/DNSStatusChip.vue:19
msgid "Problem"
@@ -1116,9 +1256,9 @@ msgstr ""
msgid "Proceed"
msgstr ""
#: src/components/layout/Navbar.vue:100 src/components/layout/Navbar.vue:127
#: src/views/user/Profile.vue:3 src/components/layout/Navbar.vue:215
#: src/components/layout/Navbar.vue:242
#: src/components/layout/Navbar.vue:106 src/components/layout/Navbar.vue:133
#: src/views/user/Profile.vue:3 src/components/layout/Navbar.vue:221
#: src/components/layout/Navbar.vue:248
msgid "Profile"
msgstr ""
@@ -1131,7 +1271,7 @@ msgstr ""
msgid "Provide a CSV file where lines respect one of the following formats:"
msgstr ""
#: src/components/logs/MessageList.vue:8 src/components/logs/MessageList.vue:41
#: src/components/logs/MessageList.vue:9 src/components/logs/MessageList.vue:42
msgid "Queue ID"
msgstr ""
@@ -1212,7 +1352,7 @@ msgstr ""
msgid "Relay"
msgstr ""
#: src/views/Login.vue:17
#: src/views/Login.vue:19
msgid "Remember me"
msgstr ""
@@ -1231,6 +1371,10 @@ msgstr ""
msgid "Reseller"
msgstr ""
#: src/views/user/PasswordRecoverySmsTotpForm.vue:21
msgid "Resend SMS."
msgstr ""
#: src/components/user/TwoFactorAuthForm.vue:60
#: src/components/user/TwoFactorAuthForm.vue:8
msgid "Reset recovery codes"
@@ -1245,6 +1389,20 @@ msgstr ""
msgid "Resources usage"
msgstr ""
#: src/views/user/PasswordRecoverySmsTotpForm.vue:23
#: src/views/user/PasswordRecoverySmsTotpForm.vue:71
msgid "Retry reset"
msgstr ""
#: src/views/user/PasswordRecoveryChangeForm.vue:24
#: src/views/user/PasswordRecoveryForm.vue:19
#: src/views/user/PasswordRecoveryForm.vue:32
#: src/views/user/PasswordRecoverySmsTotpForm.vue:22
#: src/views/user/PasswordRecoveryForm.vue:78
#: src/views/user/PasswordRecoverySmsTotpForm.vue:70
msgid "Return to login"
msgstr ""
#: src/components/identities/AccountCreationForm.vue:21
#: src/components/identities/AccountCreationForm.vue:23
#: src/components/identities/AccountCreationForm.vue:81
@@ -1273,8 +1431,8 @@ msgstr ""
msgid "Secondary email"
msgstr ""
#: src/components/layout/Navbar.vue:106 src/views/user/Security.vue:3
#: src/components/layout/Navbar.vue:221
#: src/components/layout/Navbar.vue:112 src/views/user/Security.vue:3
#: src/components/layout/Navbar.vue:227
msgid "Security"
msgstr ""
@@ -1344,6 +1502,7 @@ msgstr ""
#: src/components/identities/AccountSenderAddresses.vue:9
#: src/components/identities/AccountSenderAddresses.vue:2
#: src/plugins/vee-validate.js:24
msgid "Specify an email address"
msgstr ""
@@ -1362,11 +1521,22 @@ msgstr ""
msgid "Start typing a name here..."
msgstr ""
#: src/components/logs/MessageList.vue:10
#: src/components/logs/MessageList.vue:43
#: src/views/domains/Domain.vue:14
msgid "Statistics"
msgstr ""
#: src/components/alarms/AlarmList.vue:9 src/components/logs/MessageList.vue:11
#: src/components/alarms/AlarmList.vue:73
#: src/components/logs/MessageList.vue:44
msgid "Status"
msgstr ""
#: src/views/user/PasswordRecoveryChangeForm.vue:19
#: src/views/user/PasswordRecoveryForm.vue:15
#: src/views/user/PasswordRecoverySmsTotpForm.vue:17
msgid "Submit"
msgstr ""
#: src/components/tools/CreationForm.vue:9
#: src/components/tools/CreationForm.vue:32
msgid "Summary"
@@ -1407,12 +1577,37 @@ msgstr ""
msgid "This page is still under construction."
msgstr ""
#: src/components/logs/MessageList.vue:11
#: src/views/user/PasswordRecoveryForm.vue:25
msgid "title"
msgstr ""
#: src/components/logs/MessageList.vue:12
#: src/components/tools/TimeSerieChart.vue:18
#: src/components/logs/MessageList.vue:44
#: src/components/logs/MessageList.vue:45
msgid "To"
msgstr ""
#: src/views/Login.vue:39 src/views/user/PasswordRecoveryChangeForm.vue:62
#: src/views/user/PasswordRecoveryForm.vue:69
#: src/views/user/PasswordRecoverySmsTotpForm.vue:46 src/views/Login.vue:99
#: src/views/user/PasswordRecoveryChangeForm.vue:122
#: src/views/user/PasswordRecoveryForm.vue:115
#: src/views/user/PasswordRecoverySmsTotpForm.vue:94
msgid "Too many unsuccessful attempts, please try later."
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:33
#: src/components/dmarc/DmarcSourceTable.vue:8
#: src/components/dmarc/DmarcSourceTable.vue:3
#: src/components/dmarc/DmarcAligmentChart.vue:151
msgid "Total"
msgstr ""
#: src/views/user/PasswordRecoverySmsTotpForm.vue:37
#: src/views/user/PasswordRecoverySmsTotpForm.vue:85
msgid "TOTP resent."
msgstr ""
#: src/components/domains/DomainCreationForm.vue:77
#: src/components/domains/DomainCreationForm.vue:117
#: src/components/domains/DomainForm.vue:89
@@ -1421,6 +1616,14 @@ msgstr ""
msgid "Transport"
msgstr ""
#: src/components/alarms/AlarmList.vue:8 src/components/alarms/AlarmList.vue:72
msgid "Triggered"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:40
msgid "Trusted sources"
msgstr ""
#: src/components/user/TwoFactorAuthForm.vue:4
msgid "Two factor authentication"
msgstr ""
@@ -1449,6 +1652,10 @@ msgstr ""
msgid "Unknown"
msgstr ""
#: src/components/dmarc/DmarcAligmentChart.vue:43
msgid "Unknown sources / Threats"
msgstr ""
#: src/components/identities/AccountMailboxForm.vue:30
#: src/components/identities/AccountMailboxForm.vue:69
msgid "unlimited"
@@ -1478,6 +1685,15 @@ msgstr ""
msgid "Use domain default value"
msgstr ""
#: src/views/user/PasswordRecoverySmsTotpForm.vue:43
msgid "User seems wrong, return to login or restart reset the process?"
msgstr ""
#: src/views/user/PasswordRecoveryChangeForm.vue:56
#: src/views/user/PasswordRecoveryChangeForm.vue:116
msgid "User unknown."
msgstr ""
#: src/components/domains/AdministratorList.vue:18
#: src/components/identities/AccountCreationForm.vue:29
#: src/components/identities/AccountGeneralForm.vue:19 src/views/Login.vue:9
@@ -1517,8 +1733,8 @@ msgstr ""
msgid "Warning"
msgstr ""
#: src/components/tools/TimeSerieChart.vue:52
#: src/components/tools/TimeSerieChart.vue:110
#: src/components/tools/TimeSerieChart.vue:51
#: src/components/tools/TimeSerieChart.vue:109
msgid "Week"
msgstr ""
@@ -1535,8 +1751,8 @@ msgstr ""
msgid "With mailbox"
msgstr ""
#: src/components/tools/TimeSerieChart.vue:54
#: src/components/tools/TimeSerieChart.vue:112
#: src/components/tools/TimeSerieChart.vue:53
#: src/components/tools/TimeSerieChart.vue:111
msgid "Year"
msgstr ""
@@ -1593,6 +1809,10 @@ msgstr ""
msgid "This field is required"
msgstr ""
#: src/plugins/vee-validate.js:33
#: src/plugins/vee-validate.js:37
msgid "Invalid password"
msgstr ""
#: src/api/repository.js:38
msgid "You are throttled, please try later."
msgstr ""
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+29 -3
View File
@@ -1,10 +1,29 @@
#!/usr/bin/env python
import os
import polib
LOCALES = [
"br",
"cs",
"de",
"el",
"es",
"fi",
"fr",
"it",
"ja",
"nl",
"pt",
"pt-br",
"pl",
"po",
"ru",
"sv",
"tr",
"zh-hant",
]
OLD_TRANSLATION_MODULES = [
@@ -16,16 +35,23 @@ OLD_TRANSLATION_MODULES = [
"maillog",
"policyd",
"relaydomains",
"transport"
"transport",
"dmarc",
]
def merge_translations():
for locale in LOCALES:
new_po = polib.pofile(f"locale/{locale}/LC_MESSAGES/app.po")
target = f"locale/{locale}/LC_MESSAGES/app.po"
print(f"Opening {target}")
new_po = polib.pofile(target)
for module in OLD_TRANSLATION_MODULES:
prefix = f"../modoboa/{module}" if module else "../modoboa"
old_po = polib.pofile(f"{prefix}/locale/{locale}/LC_MESSAGES/django.po")
old_file = f"{prefix}/locale/{locale}/LC_MESSAGES/django.po"
if not os.path.exists(old_file):
continue
print(f"Opening {old_file}")
old_po = polib.pofile(old_file)
for entry in new_po:
old_entry = old_po.find(entry.msgid)
if old_entry:
+1
View File
@@ -13,6 +13,7 @@
"@mdi/font": "^5.9.55",
"apexcharts": "^3.25.0",
"core-js": "^3.6.5",
"debounce": "^1.2.1",
"js-cookie": "^2.2.1",
"luxon": "^1.28.1",
"vee-validate": "^3.4.5",
+6
View File
@@ -13,6 +13,12 @@ export default {
getDomainDNSDetail (domainId) {
return repository.get(`/${domainResource}/${domainId}/dns_detail/`)
},
getDomainDmarcAlignment (domainId, period) {
return repository.get(
`${domainResource}/${domainId}/dmarc/alignment_stats/`,
{ params: { period } }
)
},
getDomainAliases (domain) {
let url = `/${domainAliasResource}/`
if (domain !== undefined) {
+4 -1
View File
@@ -63,7 +63,7 @@
<script>
import alarms from '@/api/alarms'
import debounce from 'debounce'
export default {
data () {
return {
@@ -104,6 +104,9 @@ export default {
mounted () {
this.fetchAlarms()
},
created () {
this.fetchAlarms = debounce(this.fetchAlarms, 500)
},
watch: {
options: {
handler () {
@@ -0,0 +1,259 @@
<template>
<div v-if="alignments">
<v-card>
<v-toolbar dense elevation="0" class="mr-2">
<v-toolbar-title><translate>Alignment</translate></v-toolbar-title>
<v-spacer />
<v-btn
icon
x-small
@click="previousWeek"
>
<v-icon>mdi-arrow-left</v-icon>
</v-btn>
<span class="mx-2">{{ weekStart.toLocaleString() }} - {{ weekEnd.toLocaleString() }}</span>
<v-btn
icon
x-small
@click="nextWeek"
>
<v-icon>mdi-arrow-right</v-icon>
</v-btn>
</v-toolbar>
<v-card-text>
<v-row>
<v-col cols="5">
<apexchart
v-if="series"
type="pie"
height="350"
:options="options"
:series="series"
/>
</v-col>
<v-col cols="7">
<v-row>
<v-col
v-for="box in boxes"
:key="box.key"
cols="6"
>
<v-sheet
outlined
:color="box.color"
rounded
>
<v-card
outlined
class="pa-10 text-center"
>
<span :class="'text-h4 ' + getTextColors(box.color)">{{ stats[box.key] }}</span><br>
<span class="text-subtitle-1">{{ box.label }}</span>
</v-card>
</v-sheet>
</v-col>
</v-row>
</v-col>
</v-row>
</v-card-text>
</v-card>
<v-expansion-panels
v-model="panel"
class="mt-2"
>
<v-expansion-panel>
<v-expansion-panel-header>
<translate>Detail</translate>
</v-expansion-panel-header>
<v-expansion-panel-content>
<dmarc-source-table
:title="'Trusted sources'|translate"
color="green"
:total="stats.aligned"
:sources="alignments.aligned"
/>
<dmarc-source-table
:title="'Partially trusted sources / Forwarders'|translate"
color="orange"
:total="stats.trusted"
:sources="alignments.trusted"
class="mt-4"
/>
<dmarc-source-table
:title="'Forwarders with ARC'|translate"
color="blue"
:total="stats.forwarded"
:sources="alignments.forwarded"
class="mt-4"
/>
<dmarc-source-table
:title="'Unknown sources / Threats'|translate"
color="red"
:total="stats.failed"
:sources="alignments.failed"
class="mt-4"
/>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</div>
<div v-else>
<v-alert
v-if="dmarcDisabled"
type="info"
outlined
prominent
border="left"
class="mt-6"
>
<translate tag="div">
DMARC support does not seem to be enabled for this domain.</translate>
<translate tag="div">
If you configured it recently, please wait for the first report to be received and processed.
</translate>
</v-alert>
</div>
</template>
<script>
import colors from 'vuetify/lib/util/colors'
import DmarcSourceTable from './DmarcSourceTable'
import domainsApi from '@/api/domains'
import { DateTime } from 'luxon'
import VueApexCharts from 'vue-apexcharts'
const order = ['aligned', 'trusted', 'forwarded', 'failed']
export default {
components: {
apexchart: VueApexCharts,
DmarcSourceTable
},
props: {
domain: Object
},
data () {
return {
options: {
colors: [colors.green.lighten2, colors.orange.lighten2, colors.blue.lighten2, colors.red.lighten2],
labels: [
this.$gettext('Fully aligned'),
this.$gettext('Partially aligned'),
this.$gettext('Forwarded'),
this.$gettext('Failed')
],
legend: {
position: 'bottom'
}
},
alignments: null,
boxes: [
{ key: 'total', label: this.$gettext('Total'), color: 'primary lighten-2' },
{ key: 'aligned', label: this.$gettext('Fully aligned'), color: 'green lighten-2' },
{ key: 'trusted', label: this.$gettext('Partially aligned'), color: 'orange lighten-2' },
{ key: 'forwarded', label: this.$gettext('Forwarded'), color: 'blue lighten-2' },
{ key: 'failed', label: this.$gettext('Failed'), color: 'red lighten-2' }
],
currentWeek: 0,
currentYear: 0,
dmarcDisabled: false,
loading: false,
panel: null,
series: [],
stats: {}
}
},
computed: {
weekStart () {
const dt = DateTime.fromObject({
weekYear: this.currentYear,
weekNumber: this.currentWeek
})
return dt.startOf('week')
},
weekEnd () {
const dt = DateTime.fromObject({
weekYear: this.currentYear,
weekNumber: this.currentWeek
})
return dt.endOf('week')
}
},
methods: {
getTextColors (value) {
let result = ''
for (const color of value.split(' ')) {
if (result !== '') {
result += ' '
}
if (color.startsWith('lighten')) {
result += 'text--' + color
} else {
result += color + '--text'
}
}
return result
},
nextWeek () {
if (this.currentWeek === 52) {
this.currentYear += 1
this.currentWeek = 1
} else {
this.currentWeek += 1
}
},
previousWeek () {
if (this.currentWeek === 1) {
this.currentYear -= 1
this.currentWeek = 52
} else {
this.currentWeek -= 1
}
},
fetchAlignmentStats () {
if (this.loading) {
return
}
const period = `${this.currentYear}-${this.currentWeek}`
this.loading = true
domainsApi.getDomainDmarcAlignment(this.domain.pk, period).then(resp => {
this.loading = false
if (resp.status === 204) {
this.dmarcDisabled = true
return
}
this.stats = { total: 0 }
this.alignments = resp.data
this.series = []
for (const key of order) {
let total = 0
for (const name in resp.data[key]) {
for (const ip in resp.data[key][name]) {
total += resp.data[key][name][ip].total
}
}
this.stats.total += total
this.stats[key] = total
this.series.push(total)
}
})
}
},
created () {
const now = DateTime.now()
this.currentYear = now.year
this.currentWeek = now.weekNumber
},
mounted () {
this.fetchAlignmentStats()
},
watch: {
currentWeek () {
this.fetchAlignmentStats()
},
currentYear () {
this.fetchAlignmentStats()
}
}
}
</script>
@@ -0,0 +1,60 @@
<template>
<div>
<div class="text-h6">{{ title }} <span :class="`${color}--text text--lighten-2`">{{ total }}</span></div>
<v-simple-table>
<tbody>
<template v-for="(source, name) in sources">
<tr :key="name">
<th width="40%">{{ name }}</th>
<th><translate>Total</translate></th>
<th>SPF</th>
<th>DKIM</th>
</tr>
<tr v-for="(counters, ip) in source" :key="ip">
<td>{{ ip }}</td>
<td>{{ counters.total }}</td>
<td>
<v-avatar
color="green lighten-2"
size="24"
>
<span class="white--text">{{ counters.spf.success }}</span>
</v-avatar>
<v-avatar
color="red lighten-2 ml-1"
size="24"
>
<span class="white--text">{{ counters.spf.failure }}</span>
</v-avatar>
</td>
<td>
<v-avatar
color="green lighten-2"
size="24"
>
<span class="white--text">{{ counters.dkim.success }}</span>
</v-avatar>
<v-avatar
color="red lighten-2 ml-1"
size="24"
>
<span class="white--text">{{ counters.dkim.failure }}</span>
</v-avatar>
</td>
</tr>
</template>
</tbody>
</v-simple-table>
</div>
</template>
<script>
export default {
props: {
title: String,
color: String,
total: Number,
sources: Object
}
}
</script>
@@ -31,7 +31,7 @@
<script>
import logs from '@/api/logs'
import debounce from 'debounce'
export default {
data () {
return {
@@ -80,6 +80,9 @@ export default {
})
}
},
created () {
this.fetchLogs = debounce(this.fetchLogs, 500)
},
watch: {
options: {
handler () {
@@ -32,6 +32,7 @@
<script>
import logs from '@/api/logs'
import debounce from 'debounce'
export default {
data () {
@@ -70,6 +71,9 @@ export default {
})
}
},
created () {
this.fetchMessages = debounce(this.fetchMessages, 500)
},
watch: {
options: {
handler () {
File diff suppressed because one or more lines are too long
+7 -2
View File
@@ -13,6 +13,7 @@
<validation-provider
v-slot="{ errors }"
vid="code"
name="code"
rules="required"
>
<v-row>
@@ -24,13 +25,14 @@
:error-messages="errors"
:hint="'Enter the code from the two-factor app on your mobile device. If you have lost your device, you may enter one of your recovery codes.'|translate"
persistent-hint
@finish="verifyCode"
/>
</v-col>
</v-row>
</validation-provider>
</validation-observer>
<div class="d-flex justify-center mt-6">
<v-btn class="flex-grow-1" color="primary" large @click="verifyCode">
<v-btn class="flex-grow-1" color="primary" large @click="verifyCode" :loading="loading">
<translate>Verify code</translate>
</v-btn>
</div>
@@ -46,7 +48,8 @@ export default {
data () {
return {
code: null,
errors: {}
errors: {},
loading: false
}
},
methods: {
@@ -55,6 +58,7 @@ export default {
if (!isValid) {
return
}
this.loading = true
account.verifyTFACode(this.code).then(resp => {
Cookies.set('token', resp.data.access, { sameSite: 'strict' })
Cookies.set('refreshToken', resp.data.refresh, { sameSite: 'strict' })
@@ -63,6 +67,7 @@ export default {
})
}).catch(error => {
this.$refs.observer.setErrors(error.response.data)
this.loading = false
})
}
}
+76 -42
View File
@@ -6,49 +6,77 @@
<v-icon>mdi-circle-edit-outline</v-icon>
</v-btn>
</v-toolbar>
<v-layout>
<v-row>
<v-col cols="6">
<domain-summary :domain="domain" />
<div class="mt-4" />
<administrator-list
<v-tabs
v-model="tab"
>
<v-tab>
<translate>General</translate>
</v-tab>
<v-tab>
<translate>Statistics</translate>
</v-tab>
<v-tab>
<translate>DMARC</translate>
</v-tab>
<v-tabs-items
v-model="tab"
>
<v-tab-item>
<v-layout class="pa-2">
<v-row>
<v-col cols="6">
<domain-summary :domain="domain" />
<div class="mt-4" />
<administrator-list
:domain="domain"
/>
</v-col>
<v-col cols="6">
<dns-detail v-model="domain" />
<div class="mt-4" />
<resources
v-if="limitsConfig.params && limitsConfig.params.enable_domain_limits && domain.resources && domain.resources.length"
:resources="domain.resources"
/>
</v-col>
</v-row>
</v-layout>
</v-tab-item>
<v-tab-item>
<v-layout class="pa-2">
<v-row class="mt-2">
<v-col cols="12">
<time-serie-chart
v-if="domain.name"
:domain="domain"
graphic-set="mailtraffic"
graphic-name="averagetraffic"
/>
</v-col>
<v-col cols="12">
<time-serie-chart
v-if="domain.name"
:domain="domain"
graphic-set="mailtraffic"
graphic-name="averagetrafficsize"
/>
</v-col>
</v-row>
</v-layout>
</v-tab-item>
<v-tab-item>
<dmarc-aligment-chart
:domain="domain"
/>
</v-col>
<v-col cols="6">
<dns-detail v-model="domain" />
<div class="mt-4" />
<resources
v-if="limitsConfig.params && limitsConfig.params.enable_domain_limits && domain.resources && domain.resources.length"
:resources="domain.resources"
/>
</v-col>
</v-row>
</v-layout>
<v-layout>
<v-row class="mt-2">
<v-col cols="12">
<time-serie-chart
v-if="domain.name"
:domain="domain"
graphic-set="mailtraffic"
graphic-name="averagetraffic"
/>
</v-col>
<v-col cols="12">
<time-serie-chart
v-if="domain.name"
:domain="domain"
graphic-set="mailtraffic"
graphic-name="averagetrafficsize"
/>
</v-col>
</v-row>
</v-layout>
<v-dialog v-model="showEditForm"
persistent
max-width="800px"
>
</v-tab-item>
</v-tabs-items>
</v-tabs>
<v-dialog
v-model="showEditForm"
persistent
max-width="800px"
>
<domain-form :domain="domain" @close="showEditForm = false" />
</v-dialog>
</div>
@@ -57,6 +85,7 @@
<script>
import domains from '@/api/domains'
import AdministratorList from '@/components/domains/AdministratorList'
import DmarcAligmentChart from '@/components/dmarc/DmarcAligmentChart'
import DNSDetail from '@/components/domains/DNSDetail'
import DomainForm from '@/components/domains/DomainForm'
import DomainSummary from '@/components/domains/DomainSummary'
@@ -68,6 +97,7 @@ export default {
components: {
AdministratorList,
'dns-detail': DNSDetail,
DmarcAligmentChart,
DomainForm,
DomainSummary,
Resources,
@@ -78,7 +108,8 @@ export default {
domain: { pk: this.$route.params.id },
limitsConfig: {},
showEditForm: false,
showAdminList: false
showAdminList: false,
tab: null
}
},
methods: {
@@ -98,4 +129,7 @@ export default {
.v-toolbar {
background-color: #f7f8fa !important;
}
.v-tabs-items {
background-color: #f7f8fa !important;
}
</style>
+5
View File
@@ -3002,6 +3002,11 @@ de-indent@^1.0.2:
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
debounce@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
debug@2.6.9, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
File diff suppressed because it is too large Load Diff
+23 -14
View File
@@ -1,17 +1,20 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Irriep Nala Novram <allannkorh@yahoo.fr>, 2019
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2019-03-08 09:15+0000\n"
"Last-Translator: Irriep Nala Novram <allannkorh@yahoo.fr>\n"
"Language-Team: Breton (http://www.transifex.com/tonio/modoboa/language/br/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Breton (https://www.transifex.com/tonio/teams/13749/br/)\n"
"Language: br\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -22,19 +25,19 @@ msgstr ""
"19) && (n%100 < 70 || n%100 > 79) && (n%100 < 90 || n%100 > 99) ? 2 :(n != 0 "
"&& n % 1000000 == 0) ? 3 : 4);\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Domani ebet ken da ziskouez"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Na zilamit ket ar c'havlec'h domanioù"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "An oberiadenn-mañ a zilamo an HOLL roadennoù stag ouzh an domani-mañ."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -42,18 +45,24 @@ msgstr ""
"An oberiadenn-mañ a zilamo an HOLL roadennoù stag ouzh an domani-mañ, paneve "
"ar c'hontoù."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Kota ebet ken da ziskouez"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Kota ebet ken da ziskouez"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Merour domani ebet termenet"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Identelezh ebet ken da ziskouez"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Na zilamit ket kavlec'h ar voest-posteloù"
File diff suppressed because it is too large Load Diff
@@ -1,18 +1,21 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Miroslav Abrahám <miris@kunago.com>, 2013,2015
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-09-22 09:50+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: Czech (Czech Republic) (http://www.transifex.com/tonio/"
"modoboa/language/cs_CZ/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Czech (Czech Republic) (https://www.transifex.com/tonio/"
"teams/13749/cs_CZ/)\n"
"Language: cs_CZ\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -20,37 +23,43 @@ msgstr ""
"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n "
"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Žádná další doména k zobrazení"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Nemazat adresář domény"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Tento krok odstraní VŠECHNA data související s touto doménou."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr ""
"Tento krok odstraní VŠECHNA data související s touto doménou, vyjma účtů."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Žádná další kvóta k zobrazení"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Žádná další kvóta k zobrazení"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Není určen správce domény"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Žádná další identita k zobrazení"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Nemazat adresář schránky"
File diff suppressed because it is too large Load Diff
+23 -15
View File
@@ -1,37 +1,39 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Arvedui <arvedui@posteo.de>, 2014
# Patrick Koetter <p@state-of-mind.de>, 2010
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-09-22 09:50+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: German (http://www.transifex.com/tonio/modoboa/language/de/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: German (https://www.transifex.com/tonio/teams/13749/de/)\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Keine weiteren Domains"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Verzeichnis der Domain nicht löschen"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Diese Aktion wird ALLE mit der Domain verbundenen Daten löschen."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -39,18 +41,24 @@ msgstr ""
"Diese Aktion wird ALLE mit der Domain verbundenen Daten, außer Mailkonten, "
"löschen."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Keine weiteren Quotas"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Keine weiteren Quotas"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Domain-Administrator fehlt"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Keine weiteren Identitäten"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Verzeichnis der Mailbox nicht löschen"
File diff suppressed because it is too large Load Diff
@@ -1,40 +1,42 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Giannis Kapetanakis <bilias@edu.physics.uoc.gr>, 2016
# Kostas Moumouris <moumouriskostas@gmail.com>, 2017
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-10-05 20:01+0000\n"
"Last-Translator: Kostas Moumouris <moumouriskostas@gmail.com>\n"
"Language-Team: Greek (Greece) (http://www.transifex.com/tonio/modoboa/"
"language/el_GR/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Greek (Greece) (https://www.transifex.com/tonio/teams/13749/"
"el_GR/)\n"
"Language: el_GR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Δεν υπάρχουν άλλα domains για εμφάνιση"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Να μην διαγραφεί ο κατάλογος αρχείων του domain "
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr ""
"Αυτή η λειτουργία θα καταργήσει ΟΛΑ τα δεδομένα που σχετίζονται με αυτό το "
"domain."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -42,18 +44,24 @@ msgstr ""
"Αυτή η λειτουργία θα καταργήσει όλα τα δεδομένα που σχετίζονται με αυτό το "
"domain, εκτός από τους λογαριασμούς χρηστών."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Δεν υπάρχει κανένα quota"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Δεν υπάρχει κανένα quota"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Δεν έχει οριστεί διαχειριστής domain"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Δεν υπάρχουν άλλες ταυτότητες για εμφάνιση"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Να μην διαγραφεί ο κατάλογος αρχείων του γραμματοκιβωτίου "
File diff suppressed because it is too large Load Diff
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,36 +17,40 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr ""
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr ""
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr ""
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr ""
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr ""
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
msgid "No more log to show"
msgstr ""
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr ""
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr ""
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr ""
File diff suppressed because it is too large Load Diff
+25 -18
View File
@@ -1,39 +1,40 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Pedro Gracia <lasarux@neuroomante.com>, 2011,2013
# Pedro Gracia <pedro.gracia@impulzia.com>, 2010-2011
# samuel santos <sags9201@gmail.com>, 2017
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-02-21 00:55+0000\n"
"Last-Translator: samuel santos <sags9201@gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/tonio/modoboa/language/"
"es/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Spanish (https://www.transifex.com/tonio/teams/13749/es/)\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? "
"1 : 2;\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Sin dominios que mostrar"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "No eleminar el directorio del dominio"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Esta operación eliminará TODOS los datos asociados a este dominio."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -41,18 +42,24 @@ msgstr ""
"Esta operación eliminará todos los datos asociados a este dominio, excepto "
"las cuentas."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Sin cuota para mostrar"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Sin cuota para mostrar"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "No hay un administrador de dominio definido"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Sin identidades que mostrar"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "No eliminar el directorio del mailbox"
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,55 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-02-17 16:48+0100\n"
"PO-Revision-Date: 2023-02-17 20:10+0200\n"
"Last-Translator: Ossi Mantylahti <ossiman@gmail.com>\n"
"Language-Team: \n"
"Language: fi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.2.2\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Ei enää verkkotunnusta näytettäväksi"
#: admin/static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Älä poista verkkotunnuksen hakemistoa"
#: admin/static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr ""
"Tämä toiminto poistaa KAIKKI tähän verkkotunnukseen liittyvät tiedot."
#: admin/static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr ""
"Tämä toiminto poistaa kaikki tähän verkkotunnukseen liittyvät tiedot "
"lukuun ottamatta tilejä."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
msgid "No more quota to show"
msgstr "Ei enää kiintiöitä näytettäväksi"
#: admin/static/admin/js/admin.js:306
msgid "No domain administrator defined"
msgstr "Verkkotunnuksen ylläpitäjää ei ole määritetty"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
msgid "No more identity to show"
msgstr "Ei enää identiteettiä näytettäväksi"
#: admin/static/admin/js/admin.js:404
msgid "Do not delete mailbox directory"
msgstr "Älä poista postilaatikkohakemistoa"
File diff suppressed because it is too large Load Diff
+21 -17
View File
@@ -1,54 +1,58 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
#
# Translators:
# Antoine Nguyen <tonio@ngyn.org>, 2023
# Christophe CHAUVET <christophe.chauvet@gmail.com>, 2018
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-09-22 09:50+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2015-06-03 15:50+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: French (http://www.transifex.com/tonio/modoboa/language/fr/)\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Language: fr\n"
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Plus de domaine à afficher"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Ne pas supprimer le répertoire du domaine"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Cette opération supprimera TOUTES les données associées à ce domaine."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr ""
"Cette opération supprimera toutes les données associées à ce domaine à "
"l'exception des comptes."
msgstr "Cette opération supprimera toutes les données associées à ce domaine à l'exception des comptes."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Plus de quota à afficher"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
msgid "No more log to show"
msgstr "Plus aucun journal à afficher"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Aucun administrateur de domaine défini"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Plus d'identité à afficher"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Ne pas supprimer le répertoire de la boite aux lettres"
File diff suppressed because it is too large Load Diff
+25 -16
View File
@@ -1,37 +1,40 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Rocco <mors10@hotmail.com>, 2015
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-09-22 09:50+0000\n"
"Last-Translator: Rocco <mors10@hotmail.com>\n"
"Language-Team: Italian (http://www.transifex.com/tonio/modoboa/language/"
"it/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Italian (https://www.transifex.com/tonio/teams/13749/it/)\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? "
"1 : 2;\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Non ci sono altri domini da mostrare"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Non eliminare la cartella dei domini"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Questa operazione eliminerà TUTTI i dati associati a questo dominio."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -39,18 +42,24 @@ msgstr ""
"Questa operazione eliminerà tutti i dati associati a questo dominio tranne "
"gli account"
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Non ci sono altre quote da mostrare"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Non ci sono altre quote da mostrare"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Non è stato definito un amministratore di dominio"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Non ci sono altre identità da mostrare"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Non eliminare la cartella della casella posta"
File diff suppressed because it is too large Load Diff
@@ -1,37 +1,40 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# cwatanab <chihiro.watanabe@live.jp>, 2016
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2016-06-07 07:01+0000\n"
"Last-Translator: cwatanab <chihiro.watanabe@live.jp>\n"
"Language-Team: Japanese (Japan) (http://www.transifex.com/tonio/modoboa/"
"language/ja_JP/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Japanese (Japan) (https://www.transifex.com/tonio/teams/13749/"
"ja_JP/)\n"
"Language: ja_JP\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "表示するドメインはありません。"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "ドメインディレクトリを削除しないでください"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "この操作は、このドメインに関連するすべてのデータを削除します。"
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -39,18 +42,24 @@ msgstr ""
"この操作は、アカウントを除いたこのドメインに関連するすべてのデータを削除しま"
"す。"
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "表示するクォータはありません"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "表示するクォータはありません"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "ドメイン管理者が指定されていません"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "表示する ID はありません"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "メールボックスディレクトリを削除しないでください"
File diff suppressed because it is too large Load Diff
@@ -1,58 +1,60 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
#
# Translators:
# Harrie v.d. Vegt <hvdvegt@gmail.com>, 2016
# J Rosier <vertalen@tagora.nl>, 2023
# TuxBrother <vrijwilligerswerk@wij.rs>, 2014
# Tuxis Internet Engineering V.O.F. <info@tuxis.nl>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-09-23 21:20+0000\n"
"Last-Translator: Tuxis Internet Engineering V.O.F. <info@tuxis.nl>\n"
"Language-Team: Dutch (Netherlands) (http://www.transifex.com/tonio/modoboa/"
"language/nl_NL/)\n"
"Language: nl_NL\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2015-06-03 15:50+0000\n"
"Last-Translator: J Rosier <vertalen@tagora.nl>, 2023\n"
"Language-Team: Dutch (Netherlands) (http://www.transifex.com/tonio/modoboa/language/nl_NL/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: nl_NL\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Geen domeinen meer om weer te geven"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "De map van dit domein niet verwijderen"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Deze actie zal ALLE data verwijderen die bij dit domein hoort."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr ""
"Deze actie zal alle data die bij dit domein hoort verwijderen, behalve de "
"accounts."
msgstr "Deze actie zal alle data die bij dit domein hoort verwijderen, behalve de accounts."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Geen quotum meer om weer te geven"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
msgid "No more log to show"
msgstr "Geen logbestand meer om weer te geven"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Geen domeinbeheerder toegewezen"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Geen identiteiten meer om weer te geven"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Verwijder de map van deze mailbox niet"
File diff suppressed because it is too large Load Diff
@@ -1,18 +1,21 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# sin88 <sin@sin.waw.pl>, 2016
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-09-22 09:50+0000\n"
"Last-Translator: sin88 <sin@sin.waw.pl>\n"
"Language-Team: Polish (Poland) (http://www.transifex.com/tonio/modoboa/"
"language/pl_PL/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Polish (Poland) (https://www.transifex.com/tonio/teams/13749/"
"pl_PL/)\n"
"Language: pl_PL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -21,37 +24,43 @@ msgstr ""
"%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n"
"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Brak domen do pokazania"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Nie usuwaj katalogu domeny"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Ta operacja usunie WSZYSTKIE dane powiązane z tą domeną."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr ""
"Ta operacja usunie wszystkie dane powiązana z tą domeną za wyjątkiem kont."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Brak limitów do wyświetlenia"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Brak limitów do wyświetlenia"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Nie zdefiniowano administratora domeny"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Brak tożsamości do wyświetlenia"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Nie usuwaj katalogu skrzynki pocztowej"
File diff suppressed because it is too large Load Diff
@@ -1,37 +1,41 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Paulino Michelazzo <paulino@michelazzo.com.br>, 2014
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-09-23 21:20+0000\n"
"Last-Translator: Rafael Barretto <ch3yd@hotmail.com>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/tonio/modoboa/"
"language/pt_BR/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/tonio/"
"teams/13749/pt_BR/)\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % "
"1000000 == 0 ? 1 : 2;\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Nenhum domínio a mais para mostrar"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Não remova o diretório de domínio"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Esta operação removerá TODOS os dados associados com este domínio."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -39,18 +43,24 @@ msgstr ""
"Esta operação removerá todos os dados associados com este domínio, exceto "
"contas."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Nenhuma quota a mais para mostrar"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Nenhuma quota a mais para mostrar"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Nenhum administrador de domínio definido"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Nenhuma identidade a mais para mostrar"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Não remova o diretório de caixas de mensagens"
File diff suppressed because it is too large Load Diff
@@ -1,42 +1,41 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# lusitan <lusitan@hushmail.com>, 2013
# lusitan <lusitan@hushmail.com>, 2013
# Mike C. <miguelmclara@gmail.com>, 2012
# Mike C. <miguelmclara@gmail.com>, 2012
# Mike C. <miguelmclara@gmail.com>, 2014
# Sandra Ribeiro <sandrarib@gmail.com>, 2013
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2014-12-29 12:08+0000\n"
"Last-Translator: Mike C. <miguelmclara@gmail.com>\n"
"Language-Team: Portuguese (Portugal) (http://www.transifex.com/projects/p/"
"modoboa/language/pt_PT/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Portuguese (Portugal) (https://www.transifex.com/tonio/"
"teams/13749/pt_PT/)\n"
"Language: pt_PT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % "
"1000000 == 0 ? 1 : 2;\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Não existem mais dominios para mostrar"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Não excluir o diretório do domínio"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Esta operação irá remover TODOS os dados associados a este domínio."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -44,18 +43,24 @@ msgstr ""
"Esta operação irá remover TODOS os dados associados a este domínio, excepto "
"as contas."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Não existem mais quotas para mostrar"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Não existem mais quotas para mostrar"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Não está definido nenhum administrador para o domínio"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Não existem mais identidades para mostrar"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Não excluir o diretório da caixa de correio"
File diff suppressed because it is too large Load Diff
@@ -1,18 +1,21 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Andrei-Ilie Olteanu <andrei@flashsoft.ro>, 2018
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2018-06-12 11:38+0000\n"
"Last-Translator: Andrei-Ilie Olteanu <andrei@flashsoft.ro>\n"
"Language-Team: Romanian (Romania) (http://www.transifex.com/tonio/modoboa/"
"language/ro_RO/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Romanian (Romania) (https://www.transifex.com/tonio/"
"teams/13749/ro_RO/)\n"
"Language: ro_RO\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -20,20 +23,20 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?"
"2:1));\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Nu mai sunt domenii de afișat"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Nu sterge directorul pentru domeniu"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr ""
"Această operațiune va șterge toată informația asociată cu acest domeniu."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -41,18 +44,24 @@ msgstr ""
"Această operațiune va șterge toată informația asociată cu acest domeniu, cu "
"excepția conturilor."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Nu mai există cote de afișat"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Nu mai există cote de afișat"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Nu există configurat un administartor de domeniu"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Nu mai sunt identități de afișat"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Nu sterge directorul mailbox"
File diff suppressed because it is too large Load Diff
+23 -16
View File
@@ -1,19 +1,20 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Ravil Kadyrbayev, 2015
# Yuriy Matskanyuk <umackanuk@gmail.com>, 2018
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2018-11-27 17:54+0000\n"
"Last-Translator: Yuriy Matskanyuk <umackanuk@gmail.com>\n"
"Language-Team: Russian (http://www.transifex.com/tonio/modoboa/language/"
"ru/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Russian (https://www.transifex.com/tonio/teams/13749/ru/)\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -22,19 +23,19 @@ msgstr ""
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Нет больше доменов для показа"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Не удаляйте каталог домена"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Эта операция удалит ВСЕ данные, связанные с этим доменом."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
@@ -42,18 +43,24 @@ msgstr ""
"Эта операция удалит ВСЕ данные, связанные с этим доменом, за исключением "
"аккаунтов."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Нет больше квоты для показа"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Нет больше квоты для показа"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Не указан администратор домена"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Нет личности для показа"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Не удаляйте каталог почтовых ящиков"
File diff suppressed because it is too large Load Diff
+20 -18
View File
@@ -1,56 +1,58 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
#
# Translators:
# Joaquim Homrighausen <joho@boojam.se>, 2023
# Olle Gustafsson <olle@dalnix.se>, 2013,2015
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-09-22 09:50+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: Swedish (http://www.transifex.com/tonio/modoboa/language/"
"sv/)\n"
"Language: sv\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2015-06-03 15:50+0000\n"
"Last-Translator: Joaquim Homrighausen <joho@boojam.se>, 2023\n"
"Language-Team: Swedish (http://www.transifex.com/tonio/modoboa/language/sv/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: sv\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Inga fler domäner att visa"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Radera inte domän katalog"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Denna åtgärd kommer radera ALL data associerad med den här domänen."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr ""
"Den här operationen raderar all data som är associerad med denna domän, "
"förutom konton."
msgstr "Den här operationen raderar all data som är associerad med denna domän, förutom konton."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Ingen mer kvota att visa"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
msgid "No more log to show"
msgstr "Inga fler logghändelser finns att visa"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "Ingen domänadministratör definierad"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Inga fler konton att visa"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Radera inte brevlådans katalog"
File diff suppressed because it is too large Load Diff
@@ -1,54 +1,63 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Ediz Duman <neps1192@gmail.com>, 2016
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2017-09-22 09:50+0000\n"
"Last-Translator: Ediz Duman <neps1192@gmail.com>\n"
"Language-Team: Turkish (Turkey) (http://www.transifex.com/tonio/modoboa/"
"language/tr_TR/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Turkish (Turkey) (https://www.transifex.com/tonio/teams/13749/"
"tr_TR/)\n"
"Language: tr_TR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "Gösterilecek başka domain yok"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "Domain dizini silmeyin"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "Bu işlem, bu domain ilişkili TÜM verileri kaldıracaktır."
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr "Bu işlem hesap dışında bu domain ilişkili tüm verileri kaldıracaktır."
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "Gösterilecek kota yok"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "Gösterilecek kota yok"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "domain yöneticisi tanımlanmadı"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "Gösterilecek daha fazla kimlik yok"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "Posta kutusu dizini silmeyin"
File diff suppressed because it is too large Load Diff
@@ -1,55 +1,63 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# akong <akong@aspa.idv.tw>, 2018
# Radium <ztl8702@126.com>, 2017
# Antoine Nguyen <tonio@ngyn.org>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-09 16:48+0100\n"
"PO-Revision-Date: 2018-06-29 00:40+0000\n"
"Last-Translator: akong <akong@aspa.idv.tw>\n"
"Language-Team: Chinese (Taiwan) (http://www.transifex.com/tonio/modoboa/"
"language/zh_TW/)\n"
"POT-Creation-Date: 2023-02-22 18:52+0100\n"
"PO-Revision-Date: 2023-02-22 16:16+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>, 2023\n"
"Language-Team: Chinese (Taiwan) (https://www.transifex.com/tonio/teams/13749/"
"zh_TW/)\n"
"Language: zh_TW\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: admin/static/admin/js/admin.js:129 admin/static/admin/js/admin.js:174
#: static/admin/js/admin.js:129 static/admin/js/admin.js:174
msgid "No more domain to show"
msgstr "無更多網域可展示"
#: admin/static/admin/js/admin.js:149
#: static/admin/js/admin.js:149
msgid "Do not delete domain directory"
msgstr "不可以刪除網域目錄"
#: admin/static/admin/js/admin.js:151
#: static/admin/js/admin.js:151
msgid "This operation will remove ALL data associated to this domain."
msgstr "這個操作將會刪除所有這個網域有關的資料。"
#: admin/static/admin/js/admin.js:152
#: static/admin/js/admin.js:152
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr "這個操作將會刪除所有這個網域有關的資料,除了帳號。"
#: admin/static/admin/js/admin.js:177 admin/static/admin/js/admin.js:433
#: static/admin/js/admin.js:177 static/admin/js/admin.js:436
msgid "No more quota to show"
msgstr "沒有配額可能顯示"
#: admin/static/admin/js/admin.js:306
#: static/admin/js/admin.js:180
#, fuzzy
#| msgid "No more quota to show"
msgid "No more log to show"
msgstr "沒有配額可能顯示"
#: static/admin/js/admin.js:309
msgid "No domain administrator defined"
msgstr "網域管理員未指定"
#: admin/static/admin/js/admin.js:362 admin/static/admin/js/admin.js:430
#: static/admin/js/admin.js:365 static/admin/js/admin.js:433
msgid "No more identity to show"
msgstr "沒有身份可以顯示"
#: admin/static/admin/js/admin.js:404
#: static/admin/js/admin.js:407
msgid "Do not delete mailbox directory"
msgstr "不可能刪除郵件目錄"
+19
View File
@@ -204,6 +204,25 @@ class AccountViewSetTestCase(ModoAPITestCase):
resp = self.client.post(url)
self.assertEqual(resp.status_code, 201)
def test_failed_api_token(self):
"""Simulate a failed login attempt and check that it is logged."""
url = reverse("v2:token_obtain_pair")
data = {
"username": "clearly_non_existent_user",
"password": "password"
}
with self.assertLogs(logger='modoboa.auth', level='WARNING') as log:
resp = self.client.post(url, data, format="json")
self.assertEqual(resp.status_code, 401)
self.assertIn(
"WARNING:modoboa.auth:Failed connection attempt from '127.0.0.1'"
" as user 'clearly_non_existent_user'",
log.output
)
class PasswordResetTestCase(AccountViewSetTestCase):
def __init__(self, *args, **kwargs):
+6 -5
View File
@@ -10,8 +10,9 @@ from django.contrib.auth import login
from drf_spectacular.utils import extend_schema
from rest_framework import response, status
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_simplejwt import views as jwt_views
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
from rest_framework_simplejwt.exceptions import InvalidToken
from rest_framework.views import APIView
from modoboa.core.password_hashers import get_password_hasher
@@ -28,7 +29,7 @@ logger = logging.getLogger("modoboa.auth")
def delete_cache_key(class_target, throttles, request):
"""Attempt to delete cache key from throttling on login/password reset success."""
for throttle in throttles:
if type(throttle) == class_target:
throttle.reset_cache(request)
@@ -44,11 +45,11 @@ class TokenObtainPairView(jwt_views.TokenObtainPairView):
serializer = self.get_serializer(data=request.data)
try:
serializer.is_valid(raise_exception=True)
except TokenError as e:
except AuthenticationFailed as e:
logger.warning(
_("Failed connection attempt from '%s' as user '%s'"),
request.META["REMOTE_ADDR"],
escape(serializer.data["username"])
escape(serializer.initial_data["username"])
)
raise InvalidToken(e.args[0])
@@ -133,7 +134,7 @@ class DefaultPasswordResetView(EmailPasswordResetView):
serializer.is_valid(raise_exception=True)
except serializers.NoSMSAvailable:
return super().post(request, *args, **kwargs)
# SMS response
return response.Response({"type": "sms"}, 200)
@@ -88,6 +88,7 @@ MODOBOA_APPS = (
'modoboa.policyd',
'modoboa.maillog',
'modoboa.pdfcredentials',
'modoboa.dmarc',
# Modoboa extensions here.
{% for extension in extensions %} '{{ extension }}',
{% endfor %}
+1
View File
@@ -28,6 +28,7 @@ LANGUAGES = (
("en", u"english"),
("el", u"ελληνικά"),
("es", u"español"),
("fi", "Suomalainen"),
("fr", u"français"),
("it", u"italiano"),
("ja", u"日本の"),
@@ -0,0 +1,18 @@
# Generated by Django 3.2.16 on 2023-02-23 14:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0023_auto_20221012_0911'),
]
operations = [
migrations.AlterField(
model_name='user',
name='language',
field=models.CharField(choices=[('br', 'breton'), ('cs', 'čeština'), ('de', 'deutsch'), ('en', 'english'), ('el', 'ελληνικά'), ('es', 'español'), ('fi', 'Suomalainen'), ('fr', 'français'), ('it', 'italiano'), ('ja', '日本の'), ('nl', 'nederlands'), ('pt', 'português'), ('pt-br', 'português (BR)'), ('pl', 'polski'), ('ro', 'Română'), ('ru', 'русский'), ('sv', 'svenska'), ('tr', 'türk'), ('zh-hant', '中文(台灣)')], default='en', help_text='Prefered language to display pages.', max_length=10, verbose_name='language'),
),
]
+1 -1
View File
@@ -7,7 +7,7 @@ from django.utils.encoding import smart_text
from modoboa.core.password_hashers.advanced import ( # NOQA:F401
BLFCRYPTHasher, MD5CRYPTHasher, SHA256CRYPTHasher, SHA512CRYPTHasher,
ARGON2IDHasher
ARGON2IDHasher, SSHAHasher
)
from modoboa.core.password_hashers.base import ( # NOQA:F401
CRYPTHasher, MD5Hasher, PLAINHasher, SHA256Hasher
+20 -1
View File
@@ -4,7 +4,7 @@ Advanced (ie. stronger) password hashers.
This module relies on `passlib` to provide more secure hashers.
"""
from passlib.hash import bcrypt, md5_crypt, sha256_crypt, sha512_crypt
from passlib.hash import bcrypt, md5_crypt, sha256_crypt, sha512_crypt, ldap_salted_sha1
try:
from argon2 import PasswordHasher as argon2_hasher
@@ -113,6 +113,25 @@ class SHA512CRYPTHasher(PasswordHasher):
return sha512_crypt.verify(clearvalue, hashed_value)
class SSHAHasher(PasswordHasher):
"""
Salted SHA1 password hasher.
"""
_weak = True
@property
def scheme(self):
return "{SSHA}"
def _encrypt(self, clearvalue, salt=None):
# We have to remove the {SSHA} at the beginning of the string
return ldap_salted_sha1.hash(clearvalue)[6:]
def verify(self, clearvalue, hashed_value):
# We have to add the scheme for the hashed_value to be validated
return ldap_salted_sha1.verify(clearvalue, f'{{SSHA}}{hashed_value}')
if argon2_hasher is not None:
class ARGON2IDHasher(PasswordHasher):
"""
+8 -1
View File
@@ -110,6 +110,12 @@ class AuthenticationTestCase(ModoTestCase):
user.refresh_from_db()
self.assertTrue(user.password.startswith("{SHA256}"))
self.client.logout()
self.set_global_parameter("password_scheme", "ssha")
self.client.post(reverse("core:login"), data)
user.refresh_from_db()
self.assertTrue(user.password.startswith("{SSHA}"))
if argon2 is not None:
self.client.logout()
self.set_global_parameter("password_scheme", "argon2id")
@@ -176,7 +182,7 @@ class AuthenticationTestCase(ModoTestCase):
"""Validate Dovecot supported schemes with fake command output."""
exec_cmd_mock.return_value = (
0,
"MD5 MD5-CRYPT SHA SHA1 SHA256 SHA512 SMD5 SSHA SSHA256 SSHA512 "
"MD5 MD5-CRYPT SHA SHA1 SSHA SHA256 SHA512 SMD5 SSHA SSHA256 SSHA512 "
"PLAIN CLEAR CLEARTEXT PLAIN-TRUNC CRAM-MD5 SCRAM-SHA-1 HMAC-MD5 "
"DIGEST-MD5 PLAIN-MD4 PLAIN-MD5 LDAP-MD5 LANMAN NTLM OTP SKEY RPA "
"PBKDF2 CRYPT SHA256-CRYPT SHA512-CRYPT"
@@ -187,6 +193,7 @@ class AuthenticationTestCase(ModoTestCase):
"{MD5-CRYPT}",
"{SHA}",
"{SHA1}",
"{SSHA}",
"{SHA256}",
"{SHA512}",
"{SMD5}",
+2 -1
View File
@@ -106,7 +106,8 @@ SETTINGS_SAMPLE = {
"pdfcredentials-smtp_connection_security": "starttls",
"pdfcredentials-imap_server_address": "127.0.0.1",
"pdfcredentials-imap_server_port": 667,
"pdfcredentials-imap_connection_security": "starttls"
"pdfcredentials-imap_connection_security": "starttls",
"dmarc-enable_rlookups": False,
}
+3
View File
@@ -0,0 +1,3 @@
"""DMARC related tools for Modoboa."""
default_app_config = "modoboa.dmarc.apps.DmarcConfig"
+3
View File
@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.
View File
View File
+32
View File
@@ -0,0 +1,32 @@
"""App related serializers."""
from rest_framework import serializers
class TestResultSerializer(serializers.Serializer):
success = serializers.IntegerField()
failure = serializers.IntegerField()
class SourceSerializer(serializers.Serializer):
total = serializers.IntegerField()
spf = TestResultSerializer()
dkim = TestResultSerializer()
class DMARCAligmentSerializer(serializers.Serializer):
aligned = serializers.DictField(
child=serializers.DictField(child=SourceSerializer())
)
trusted = serializers.DictField(
child=serializers.DictField(child=SourceSerializer())
)
forwarded = serializers.DictField(
child=serializers.DictField(child=SourceSerializer())
)
failed = serializers.DictField(
child=serializers.DictField(child=SourceSerializer())
)
+36
View File
@@ -0,0 +1,36 @@
"""API v2 tests."""
from django.urls import reverse
from modoboa.lib.tests import ModoAPITestCase
from modoboa.admin import factories as admin_factories
from modoboa.dmarc.tests import mixins
class DmarcViewSetTestCase(mixins.CallCommandMixin, ModoAPITestCase):
@classmethod
def setUpTestData(cls):
"""Create test data."""
super().setUpTestData()
cls.domain = admin_factories.DomainFactory(name="ngyn.org")
def test_alignment_stats(self):
"""Test alignment stats endpoint."""
self.import_reports()
url = reverse("v2:dmarc-alignment-stats", args=[self.domain.pk])
response = self.client.get(f"{url}?period=2015-26")
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()["failed"]), 1)
def test_no_record(self):
url = reverse("v2:dmarc-alignment-stats", args=[self.domain.pk])
response = self.client.get(f"{url}?period=2015-26")
self.assertEqual(response.status_code, 204)
def test_wrong_range(self):
self.import_reports()
url = reverse("v2:dmarc-alignment-stats", args=[self.domain.pk])
response = self.client.get(f"{url}?period=toto-titi")
self.assertEqual(response.status_code, 400)
+10
View File
@@ -0,0 +1,10 @@
"""App related API urls."""
from rest_framework import routers
from . import viewsets
router = routers.SimpleRouter()
router.register(r"domains", viewsets.DMARCViewSet, basename="dmarc")
urlpatterns = router.urls
+38
View File
@@ -0,0 +1,38 @@
"""App. related viewsets."""
from rest_framework import permissions, response, viewsets
from rest_framework.decorators import action
from modoboa.admin import models as admin_models
from modoboa.lib.throttle import GetThrottleViewsetMixin
from ... import lib
from . import serializers
class DMARCViewSet(GetThrottleViewsetMixin, viewsets.GenericViewSet):
permission_classes = (permissions.IsAuthenticated, )
def get_queryset(self):
"""Filter queryset based on current user."""
return admin_models.Domain.objects.get_for_admin(self.request.user)
@action(
methods=["get"],
detail=True,
serializer_class=serializers.DMARCAligmentSerializer,
url_path="dmarc/alignment_stats"
)
def alignment_stats(self, request, **kwargs):
domain = self.get_object()
if not domain.record_set.exists():
return response.Response(status=204)
try:
stats = lib.get_aligment_stats(
domain, self.request.query_params.get("period")
)
except ValueError:
return response.Response("Invalid range received", status=400)
serializer = self.get_serializer(stats)
return response.Response(serializer.data)
+16
View File
@@ -0,0 +1,16 @@
"""AppConfig for dmarc."""
from django.apps import AppConfig
from modoboa.dmarc.forms import load_settings
class DmarcConfig(AppConfig):
"""App configuration."""
name = "modoboa.dmarc"
verbose_name = "Modoboa DMARC tools"
def ready(self):
load_settings()
from . import handlers
+10
View File
@@ -0,0 +1,10 @@
"""DMARC constants."""
ALLOWED_REASON_TYPES = (
"forwarded",
"sampled_out",
"trusted_forwarder",
"mailing_list",
"local_policy",
"other"
)
+51
View File
@@ -0,0 +1,51 @@
"""Custom forms."""
from django import forms
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from modoboa.lib import form_utils
from modoboa.parameters import forms as param_forms
class ReportOptionsForm(forms.Form):
"""Report display options."""
current_year = forms.IntegerField(widget=forms.widgets.HiddenInput)
current_week = forms.IntegerField()
query = forms.ChoiceField(
choices=[("previous", "Previous"), ("next", "Next")])
resolve_hostnames = forms.BooleanField(
initial=False, required=False)
def __init__(self, *args, **kwargs):
"""Constructor."""
super().__init__(*args, **kwargs)
if not args:
year, week, day = timezone.now().isocalendar()
self.fields["current_year"].initial = year
self.fields["current_week"].initial = week
class ParametersForm(param_forms.AdminParametersForm):
"""Extension settings."""
app = "dmarc"
qsettings_sep = form_utils.SeparatorField(label=_("DNS settings"))
enable_rlookups = form_utils.YesNoField(
label=_("Enable reverse lookups"),
initial=False,
help_text=_(
"Enable reverse DNS lookups (reports will be longer to display)"
)
)
def load_settings():
"""Load app settings."""
from modoboa.parameters import tools as param_tools
param_tools.registry.add(
"global", ParametersForm, _("DMARC"))
+22
View File
@@ -0,0 +1,22 @@
"""Django signal handlers for modoboa_dmarc."""
from django.urls import reverse
from django.utils.translation import ugettext as _
from django.dispatch import receiver
from modoboa.admin import signals as admin_signals
from . import models
@receiver(admin_signals.extra_domain_actions)
def dmarc_domain_actions(sender, user, domain, **kwargs):
"""Return a link to access domain report."""
if not models.Record.objects.filter(header_from=domain).exists():
return []
return [{
"name": "dmarc_report",
"url": reverse("dmarc:domain_report", args=[domain.pk]),
"title": _("Show DMARC report for {}").format(domain.name),
"img": "fa fa-pie-chart"
}]
+309
View File
@@ -0,0 +1,309 @@
"""Internal library."""
import concurrent.futures
import datetime
import email
import fileinput
import getpass
import imaplib
import zipfile
import gzip
import sys
import tldextract
from defusedxml.ElementTree import fromstring
from dns import resolver, reversename
import magic
import pytz.exceptions
import six
from django.db import transaction
from django.db.models import Q
from django.utils import timezone
from django.utils.encoding import smart_text
from django.utils.translation import ugettext as _
from modoboa.admin import models as admin_models
from modoboa.parameters import tools as param_tools
from . import constants
from . import models
ZIP_CONTENT_TYPES = [
"application/x-zip-compressed",
"application/x-zip",
"application/zip",
"application/gzip",
"application/octet-stream",
"text/xml",
]
FILE_TYPES = [
"text/plain",
"text/xml",
]
def import_record(xml_node, report):
"""Import a record."""
record = models.Record(report=report)
row = xml_node.find("row")
record.source_ip = row.find("source_ip").text
record.count = int(row.find("count").text)
policy_evaluated = row.find("policy_evaluated")
record.disposition = policy_evaluated.find("disposition").text
record.dkim_result = policy_evaluated.find("dkim").text
record.spf_result = policy_evaluated.find("spf").text
reason = policy_evaluated.find("reason")
if reason:
record.reason_type = smart_text(reason.find("type").text)[:14]
if record.reason_type not in constants.ALLOWED_REASON_TYPES:
record.reason_type = "other"
comment = reason.find("comment").text or ""
record.reason_comment = comment
identifiers = xml_node.find("identifiers")
header_from = identifiers.find("header_from").text.split(".")
domain = None
while len(header_from) >= 2:
domain = admin_models.Domain.objects.filter(
name=".".join(header_from)).first()
if domain is not None:
record.header_from = domain
break
header_from = header_from[1:]
if domain is None:
print("Invalid record found (domain not local)")
return None
record.save()
auth_results = xml_node.find("auth_results")
for rtype in ["spf", "dkim"]:
rnode = auth_results.find(rtype)
if not rnode:
continue
models.Result.objects.create(
record=record, type=rtype, domain=rnode.find("domain").text,
result=rnode.find("result").text)
@transaction.atomic
def import_report(content):
"""Import an aggregated report."""
root = fromstring(content, forbid_dtd=True)
metadata = root.find("report_metadata")
print(
"Importing report {} received from {}".format(
metadata.find("report_id").text,
metadata.find("org_name").text)
)
reporter, created = models.Reporter.objects.get_or_create(
email=metadata.find("email").text,
defaults={"org_name": metadata.find("org_name").text}
)
qs = models.Report.objects.filter(
reporter=reporter, report_id=metadata.find("report_id").text)
if qs.exists():
print("Report already imported.")
return
report = models.Report(reporter=reporter)
report.report_id = metadata.find("report_id").text
date_range = metadata.find("date_range")
report.start_date = timezone.make_aware(
datetime.datetime.fromtimestamp(int(date_range.find("begin").text))
)
report.end_date = timezone.make_aware(
datetime.datetime.fromtimestamp(int(date_range.find("end").text))
)
policy_published = root.find("policy_published")
for attr in ["domain", "adkim", "aspf", "p", "sp", "pct"]:
node = policy_published.find(attr)
if node is None or not node.text:
if attr == "sp":
node = fromstring('<sp>unstated</sp>', forbid_dtd=True)
else:
print(f"Report skipped because of malformed data (empty {attr})")
return
value = setattr(report, "policy_{}".format(attr), node.text)
try:
report.save()
except (pytz.exceptions.AmbiguousTimeError):
print("Report skipped because of invalid date.")
return
for record in root.findall("record"):
import_record(record, report)
def import_archive(archive, content_type=None):
"""Import reports contained inside (file pointer)
- a zip archive,
- a gzip file,
- a xml file.
"""
if content_type == "text/xml":
import_report(archive.read())
elif content_type in ["application/gzip", "application/octet-stream"]:
with gzip.GzipFile(mode="r", fileobj=archive) as zfile:
import_report(zfile.read())
else:
with zipfile.ZipFile(archive, "r") as zfile:
for fname in zfile.namelist():
import_report(zfile.read(fname))
def import_report_from_email(content):
"""Import a report from an email."""
if isinstance(content, six.string_types):
msg = email.message_from_string(content)
elif isinstance(content, six.binary_type):
msg = email.message_from_bytes(content)
else:
msg = email.message_from_file(content)
err = False
for part in msg.walk():
if part.get_content_type() not in ZIP_CONTENT_TYPES:
continue
try:
fpo = six.BytesIO(part.get_payload(decode=True))
# Try to get the actual file type of the buffer
# required to make sure we are dealing with an XML file
file_type = magic.Magic(uncompress=True, mime=True).from_buffer(fpo.read(2048))
fpo.seek(0)
if file_type in FILE_TYPES:
import_archive(fpo, content_type=part.get_content_type())
except (OSError, IOError):
print('Error: the attachment does not match the mimetype')
err = True
else:
fpo.close()
if err:
# Return EX_DATAERR code <data format error> available
# at sysexits.h file
# (see http://www.postfix.org/pipe.8.html)
sys.exit(65)
def import_report_from_stdin():
"""Parse a report from stdin."""
content = six.StringIO()
for line in fileinput.input([]):
content.write(line)
content.seek(0)
if not content:
return
import_report_from_email(content)
def import_from_imap(options):
"""Import reports from an IMAP mailbox."""
obj = imaplib.IMAP4_SSL if options["ssl"] else imaplib.IMAP4
conn = obj(options["host"])
username = input("Username: ")
password = getpass.getpass(prompt="Password: ")
conn.login(username, password)
conn.select(options["mailbox"])
type, msg_ids = conn.search(None, "ALL")
for msg_id in msg_ids[0].split():
typ, content = conn.fetch(msg_id, "(RFC822)")
for response_part in content:
if isinstance(response_part, tuple):
import_report_from_email(response_part[1])
conn.close()
def week_range(year, weeknumber):
"""Return start and end dates of a given week."""
tz = timezone.get_current_timezone()
fmt = "%Y-%W-%w"
start_week = datetime.datetime.strptime(
"{}-{}-{}".format(year, weeknumber, 1), fmt)
end_week = datetime.datetime.strptime(
"{}-{}-{}".format(year, weeknumber, 0), fmt)
return tz.localize(start_week), tz.localize(end_week)
def insert_record(target: dict, record, name: str) -> None:
"""Add a record."""
if name not in target:
target[name] = {}
if record.source_ip not in target[name]:
target[name][record.source_ip] = {
"total": 0,
"spf": {"success": 0, "failure": 0},
"dkim": {"success": 0, "failure": 0}
}
target[name][record.source_ip]["total"] += record.count
for typ in ["spf", "dkim"]:
result = getattr(record, "{}_result".format(typ))
key = "success" if result == "pass" else "failure"
target[name][record.source_ip][typ][key] += record.count
def get_aligment_stats(domain, period=None) -> dict:
"""Retrieve aligment statistics for given domain."""
if not period:
year, week, day = timezone.now().isocalendar()
week -= 1
period = f"{year}-{week}"
else:
year, week = period.split("-")
if not year or not week:
period = f"{year}-{week}"
daterange = week_range(year, week)
qargs = (
(Q(report__start_date__gte=daterange[0],
report__start_date__lte=daterange[1]) |
Q(report__end_date__gte=daterange[0],
report__end_date__lte=daterange[1])) &
Q(header_from=domain)
)
all_records = models.Record.objects.filter(qargs)
stats: dict = {
"aligned": {},
"trusted": {},
"forwarded": {},
"failed": {}
}
dns_names = {}
if param_tools.get_global_parameter("enable_rlookups"):
dns_resolver = resolver.Resolver()
dns_resolver.timeout = 1.0
dns_resolver.lifetime = 1.0
def get_domain_name_from_ip(ip):
addr = reversename.from_address(ip)
try:
resp = dns_resolver.query(addr, "PTR")
ext = tldextract.extract(str(resp[0].target))
if not ext.suffix: # invalid PTR record
raise resolver.NXDOMAIN()
return (ip, '.'.join((ext.domain, ext.suffix)).lower())
except (resolver.NXDOMAIN, resolver.YXDOMAIN,
resolver.NoAnswer, resolver.NoNameservers,
resolver.Timeout):
return (None, None)
ips = (r.source_ip for r in all_records)
with concurrent.futures.ThreadPoolExecutor(max_workers=16) as pool:
dns_names = {i: n for (i, n) in
list(pool.map(get_domain_name_from_ip, ips))}
for record in all_records:
name = dns_names.get(record.source_ip, _("Not resolved"))
if record.dkim_result == "pass" and record.spf_result == "pass":
insert_record(stats["aligned"], record, name)
elif record.dkim_result == "pass" or record.spf_result == "pass":
insert_record(stats["trusted"], record, name)
elif record.reason_type == "local_policy" and record.reason_comment.startswith("arc=pass"):
insert_record(stats["forwarded"], record, name)
else:
insert_record(stats["failed"], record, name)
return stats
@@ -0,0 +1,138 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Irriep Nala Novram <allannkorh@yahoo.fr>, 2019
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-06 14:05+0200\n"
"PO-Revision-Date: 2020-05-06 12:07+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: Breton (http://www.transifex.com/tonio/modoboa/language/br/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: br\n"
"Plural-Forms: nplurals=5; plural=((n%10 == 1) && (n%100 != 11) && (n%100 !=71) && (n%100 !=91) ? 0 :(n%10 == 2) && (n%100 != 12) && (n%100 !=72) && (n%100 !=92) ? 1 :(n%10 ==3 || n%10==4 || n%10==9) && (n%100 < 10 || n% 100 > 19) && (n%100 < 70 || n%100 > 79) && (n%100 < 90 || n%100 > 99) ? 2 :(n != 0 && n % 1000000 == 0) ? 3 : 4);\n"
#: forms.py:35
msgid "DNS settings"
msgstr "Arventennoù DNS"
#: forms.py:38
msgid "Enable reverse lookups"
msgstr "Enaouiñ an enklaskoù eilpennet"
#: forms.py:41
msgid "Enable reverse DNS lookups (reports will be longer to display)"
msgstr "Enaouiñ an enklaskoù DNS eilpennet (danevelloù a vo hiroc'h da vezañ diskouezet)"
#: handlers.py:20
msgid "Show DMARC report for {}"
msgstr "Diskouez an danevell DMARC evit {}"
#: models.py:10 models.py:16
msgid "None"
msgstr "Hini ebet"
#: models.py:11
msgid "Quarantine"
msgstr "Dispell"
#: models.py:12
msgid "Reject"
msgstr "Nac'hañ"
#: models.py:17
msgid "Neutral"
msgstr "Neptu"
#: models.py:18
msgid "Pass"
msgstr "Tremen"
#: models.py:19
msgid "Fail"
msgstr "Sac'hadenn"
#: models.py:20
msgid "Temporary error"
msgstr "Fazi padennek"
#: models.py:21
msgid "Permanent error"
msgstr "Fazi peurbadus"
#: models.py:25
msgid "Policy"
msgstr "Politikerezh"
#: models.py:29
msgid "Soft failure"
msgstr "Sac'hadenn wan"
#: modo_extension.py:16
msgid "DMARC tools"
msgstr "Ostilhoù DMARC"
#: modo_extension.py:19
msgid "A set of tools to ease DMARC integration"
msgstr "Un dastumad ostilhoù da aesaat enframmañ DMARC"
#: templates/modoboa_dmarc/_result_detail.html:6
msgid "Total"
msgstr "Hollad"
#: templates/modoboa_dmarc/domain_report.html:21
#: templates/modoboa_dmarc/domain_report.html:26
msgid "Fully aligned"
msgstr "Linennet penn-da-benn"
#: templates/modoboa_dmarc/domain_report.html:22
#: templates/modoboa_dmarc/domain_report.html:27
msgid "Partially aligned"
msgstr "Linennet dre an hanter"
#: templates/modoboa_dmarc/domain_report.html:23
#: templates/modoboa_dmarc/domain_report.html:28
msgid "Failed"
msgstr "C'hwitet"
#: templates/modoboa_dmarc/domain_report.html:50
msgid "DMARC report for"
msgstr "Danevell DMARC evit"
#: templates/modoboa_dmarc/domain_report.html:74
msgid "processed"
msgstr "tretet"
#: templates/modoboa_dmarc/domain_report.html:83
msgid "fully aligned"
msgstr "linennet penn-da-benn"
#: templates/modoboa_dmarc/domain_report.html:92
msgid "partially aligned"
msgstr "linennet dre an hanter"
#: templates/modoboa_dmarc/domain_report.html:101
msgid "failed"
msgstr "c'hwitet"
#: templates/modoboa_dmarc/domain_report.html:111
msgid "Display details"
msgstr "Diskouez ar munudoù"
#: templates/modoboa_dmarc/domain_report.html:115
msgid "Trusted sources"
msgstr "Mammennoù fizius"
#: templates/modoboa_dmarc/domain_report.html:123
msgid "Unknown sources / Threats"
msgstr "Mammennoù dizanv/Gourdrouzioù"
#: templatetags/dmarc_tags.py:59 views.py:120
msgid "Not resolved"
msgstr ""
@@ -0,0 +1,139 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Jan Laufik, 2016
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-06 14:05+0200\n"
"PO-Revision-Date: 2017-03-03 08:18+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: Czech (Czech Republic) (http://www.transifex.com/tonio/"
"modoboa/language/cs_CZ/)\n"
"Language: cs_CZ\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
#: forms.py:35
msgid "DNS settings"
msgstr ""
#: forms.py:38
msgid "Enable reverse lookups"
msgstr ""
#: forms.py:41
msgid "Enable reverse DNS lookups (reports will be longer to display)"
msgstr ""
#: handlers.py:20
msgid "Show DMARC report for {}"
msgstr "Zobrazit DMARC zprávu pro {}"
#: models.py:10 models.py:16
msgid "None"
msgstr "Nic"
#: models.py:11
msgid "Quarantine"
msgstr "Karanténa"
#: models.py:12
msgid "Reject"
msgstr "Odmítnout"
#: models.py:17
msgid "Neutral"
msgstr "Neutrální"
#: models.py:18
msgid "Pass"
msgstr "Úspěch"
#: models.py:19
msgid "Fail"
msgstr "Selhání"
#: models.py:20
msgid "Temporary error"
msgstr "Dočasná chyba"
#: models.py:21
msgid "Permanent error"
msgstr "Permanentní chyba"
#: models.py:25
msgid "Policy"
msgstr "Politika"
#: models.py:29
msgid "Soft failure"
msgstr "Selhání bez odmítnutí"
#: modo_extension.py:16
msgid "DMARC tools"
msgstr "DMARC nástroje"
#: modo_extension.py:19
msgid "A set of tools to ease DMARC integration"
msgstr "Sada nástrojů pro zjednodušení integrace DMARC"
#: templates/modoboa_dmarc/_result_detail.html:6
msgid "Total"
msgstr "Celkem"
#: templates/modoboa_dmarc/domain_report.html:21
#: templates/modoboa_dmarc/domain_report.html:26
msgid "Fully aligned"
msgstr "Plně v souladu"
#: templates/modoboa_dmarc/domain_report.html:22
#: templates/modoboa_dmarc/domain_report.html:27
msgid "Partially aligned"
msgstr "Částečně v souladu"
#: templates/modoboa_dmarc/domain_report.html:23
#: templates/modoboa_dmarc/domain_report.html:28
msgid "Failed"
msgstr "Selhalo"
#: templates/modoboa_dmarc/domain_report.html:50
msgid "DMARC report for"
msgstr "DMARC zpráva pro"
#: templates/modoboa_dmarc/domain_report.html:74
msgid "processed"
msgstr "zpracované"
#: templates/modoboa_dmarc/domain_report.html:83
msgid "fully aligned"
msgstr "plně v souladu"
#: templates/modoboa_dmarc/domain_report.html:92
msgid "partially aligned"
msgstr "částečně v souladu"
#: templates/modoboa_dmarc/domain_report.html:101
msgid "failed"
msgstr "selhalo"
#: templates/modoboa_dmarc/domain_report.html:111
msgid "Display details"
msgstr "Zobrazit podrobnosti"
#: templates/modoboa_dmarc/domain_report.html:115
msgid "Trusted sources"
msgstr "Důvěryhodné zdroje"
#: templates/modoboa_dmarc/domain_report.html:123
msgid "Unknown sources / Threats"
msgstr "Neznáme zdroje / Hrozby"
#: templatetags/dmarc_tags.py:59 views.py:120
msgid "Not resolved"
msgstr ""
@@ -0,0 +1,139 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# controlc.de, 2015
# Tobias Strobel, 2016
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-06 14:05+0200\n"
"PO-Revision-Date: 2017-03-03 08:18+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: German (http://www.transifex.com/tonio/modoboa/language/de/)\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:35
msgid "DNS settings"
msgstr ""
#: forms.py:38
msgid "Enable reverse lookups"
msgstr ""
#: forms.py:41
msgid "Enable reverse DNS lookups (reports will be longer to display)"
msgstr ""
#: handlers.py:20
msgid "Show DMARC report for {}"
msgstr "DMARC-Bericht für {} anzeigen"
#: models.py:10 models.py:16
msgid "None"
msgstr "Nichts"
#: models.py:11
msgid "Quarantine"
msgstr "Quarantäne"
#: models.py:12
msgid "Reject"
msgstr "Ablehnung"
#: models.py:17
msgid "Neutral"
msgstr "Neutral"
#: models.py:18
msgid "Pass"
msgstr "Genehmigen"
#: models.py:19
msgid "Fail"
msgstr "Abbruch"
#: models.py:20
msgid "Temporary error"
msgstr "Temporärer Fehler"
#: models.py:21
msgid "Permanent error"
msgstr "Permanenter Fehler"
#: models.py:25
msgid "Policy"
msgstr "Richtlinie"
#: models.py:29
msgid "Soft failure"
msgstr "Schwacher Fehler"
#: modo_extension.py:16
msgid "DMARC tools"
msgstr "DMARC-Tools"
#: modo_extension.py:19
msgid "A set of tools to ease DMARC integration"
msgstr "Ein Set von Tools um die DMARC-Integration zu vereinfachen"
#: templates/modoboa_dmarc/_result_detail.html:6
msgid "Total"
msgstr "Total"
#: templates/modoboa_dmarc/domain_report.html:21
#: templates/modoboa_dmarc/domain_report.html:26
msgid "Fully aligned"
msgstr "Voll zugeordnet"
#: templates/modoboa_dmarc/domain_report.html:22
#: templates/modoboa_dmarc/domain_report.html:27
msgid "Partially aligned"
msgstr "Teilweise zugeordnet"
#: templates/modoboa_dmarc/domain_report.html:23
#: templates/modoboa_dmarc/domain_report.html:28
msgid "Failed"
msgstr "Fehlgeschlagen"
#: templates/modoboa_dmarc/domain_report.html:50
msgid "DMARC report for"
msgstr "DMARC-Bericht für"
#: templates/modoboa_dmarc/domain_report.html:74
msgid "processed"
msgstr "durchgeführt"
#: templates/modoboa_dmarc/domain_report.html:83
msgid "fully aligned"
msgstr "voll zugeordnet"
#: templates/modoboa_dmarc/domain_report.html:92
msgid "partially aligned"
msgstr "teilweise zugeordnet"
#: templates/modoboa_dmarc/domain_report.html:101
msgid "failed"
msgstr "fehlgeschlagen"
#: templates/modoboa_dmarc/domain_report.html:111
msgid "Display details"
msgstr "Anzeigedetails"
#: templates/modoboa_dmarc/domain_report.html:115
msgid "Trusted sources"
msgstr "Vertraute Quellen"
#: templates/modoboa_dmarc/domain_report.html:123
msgid "Unknown sources / Threats"
msgstr "Unbekannte Quellen / Bedrohungen"
#: templatetags/dmarc_tags.py:59 views.py:120
msgid "Not resolved"
msgstr ""
@@ -0,0 +1,140 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Giannis Kapetanakis <bilias@edu.physics.uoc.gr>, 2016
# Kostas Moumouris <moumouriskostas@gmail.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-06 14:05+0200\n"
"PO-Revision-Date: 2017-10-12 09:55+0000\n"
"Last-Translator: Kostas Moumouris <moumouriskostas@gmail.com>\n"
"Language-Team: Greek (Greece) (http://www.transifex.com/tonio/modoboa/"
"language/el_GR/)\n"
"Language: el_GR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:35
msgid "DNS settings"
msgstr "Ρυθμίσεις DNS"
#: forms.py:38
msgid "Enable reverse lookups"
msgstr "Ενεργοποίηση ανάστροφης αναζήτησης reverse lookups"
#: forms.py:41
msgid "Enable reverse DNS lookups (reports will be longer to display)"
msgstr "Ενεργοποίηση reverse DNS lookups (η αναφορές θα καθυστερούν)"
#: handlers.py:20
msgid "Show DMARC report for {}"
msgstr "Εμφάνιση της έκθεσης DMARC του {}"
#: models.py:10 models.py:16
msgid "None"
msgstr "Κανένα"
#: models.py:11
msgid "Quarantine"
msgstr "Καραντίνα"
#: models.py:12
msgid "Reject"
msgstr "Απόρριψη"
#: models.py:17
msgid "Neutral"
msgstr "Ουδέτερο"
#: models.py:18
msgid "Pass"
msgstr "Εγκρίθηκε"
#: models.py:19
msgid "Fail"
msgstr "Απορρίφθηκε"
#: models.py:20
msgid "Temporary error"
msgstr "προσωρινό σφάλμα"
#: models.py:21
msgid "Permanent error"
msgstr "Μόνιμο σφάλμα"
#: models.py:25
msgid "Policy"
msgstr "Πολιτική"
#: models.py:29
msgid "Soft failure"
msgstr "Πρόβλημα Soft"
#: modo_extension.py:16
msgid "DMARC tools"
msgstr "Εργαλεία DMARC"
#: modo_extension.py:19
msgid "A set of tools to ease DMARC integration"
msgstr "Ένα σετ εργαλείων για την απλοποίηση της ενσωμάτωσης του DMARC"
#: templates/modoboa_dmarc/_result_detail.html:6
msgid "Total"
msgstr "Σύνολο"
#: templates/modoboa_dmarc/domain_report.html:21
#: templates/modoboa_dmarc/domain_report.html:26
msgid "Fully aligned"
msgstr "Πλήρως ευθυγραμμισμένο"
#: templates/modoboa_dmarc/domain_report.html:22
#: templates/modoboa_dmarc/domain_report.html:27
msgid "Partially aligned"
msgstr "Μερικός ευθυγραμισμένα"
#: templates/modoboa_dmarc/domain_report.html:23
#: templates/modoboa_dmarc/domain_report.html:28
msgid "Failed"
msgstr "Απέτυχε"
#: templates/modoboa_dmarc/domain_report.html:50
msgid "DMARC report for"
msgstr "Έκθεση DMARC του"
#: templates/modoboa_dmarc/domain_report.html:74
msgid "processed"
msgstr "Επεξεργάστηκε"
#: templates/modoboa_dmarc/domain_report.html:83
msgid "fully aligned"
msgstr "πλήρως ευθυγραμμισμένο"
#: templates/modoboa_dmarc/domain_report.html:92
msgid "partially aligned"
msgstr "Μερικώς ευθυγραμμισμένο"
#: templates/modoboa_dmarc/domain_report.html:101
msgid "failed"
msgstr "απέτυχε"
#: templates/modoboa_dmarc/domain_report.html:111
msgid "Display details"
msgstr "Προβολή λεπτομερειών"
#: templates/modoboa_dmarc/domain_report.html:115
msgid "Trusted sources"
msgstr "Αξιόπιστες πηγές"
#: templates/modoboa_dmarc/domain_report.html:123
msgid "Unknown sources / Threats"
msgstr "Άγνωστες πηγές / Απειλές"
#: templatetags/dmarc_tags.py:59 views.py:120
msgid "Not resolved"
msgstr ""
@@ -0,0 +1,137 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-06 14:05+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:35
msgid "DNS settings"
msgstr ""
#: forms.py:38
msgid "Enable reverse lookups"
msgstr ""
#: forms.py:41
msgid "Enable reverse DNS lookups (reports will be longer to display)"
msgstr ""
#: handlers.py:20
msgid "Show DMARC report for {}"
msgstr ""
#: models.py:10 models.py:16
msgid "None"
msgstr ""
#: models.py:11
msgid "Quarantine"
msgstr ""
#: models.py:12
msgid "Reject"
msgstr ""
#: models.py:17
msgid "Neutral"
msgstr ""
#: models.py:18
msgid "Pass"
msgstr ""
#: models.py:19
msgid "Fail"
msgstr ""
#: models.py:20
msgid "Temporary error"
msgstr ""
#: models.py:21
msgid "Permanent error"
msgstr ""
#: models.py:25
msgid "Policy"
msgstr ""
#: models.py:29
msgid "Soft failure"
msgstr ""
#: modo_extension.py:16
msgid "DMARC tools"
msgstr ""
#: modo_extension.py:19
msgid "A set of tools to ease DMARC integration"
msgstr ""
#: templates/modoboa_dmarc/_result_detail.html:6
msgid "Total"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:21
#: templates/modoboa_dmarc/domain_report.html:26
msgid "Fully aligned"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:22
#: templates/modoboa_dmarc/domain_report.html:27
msgid "Partially aligned"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:23
#: templates/modoboa_dmarc/domain_report.html:28
msgid "Failed"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:50
msgid "DMARC report for"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:74
msgid "processed"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:83
msgid "fully aligned"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:92
msgid "partially aligned"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:101
msgid "failed"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:111
msgid "Display details"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:115
msgid "Trusted sources"
msgstr ""
#: templates/modoboa_dmarc/domain_report.html:123
msgid "Unknown sources / Threats"
msgstr ""
#: templatetags/dmarc_tags.py:59 views.py:120
msgid "Not resolved"
msgstr ""

Some files were not shown because too many files have changed in this diff Show More