Finish mail server settings

This commit is contained in:
Johannes Zellner
2025-03-10 12:44:31 +01:00
parent 15a27e234c
commit d633029d08
2 changed files with 145 additions and 17 deletions
+145 -16
View File
@@ -5,7 +5,7 @@ const i18n = useI18n();
const t = i18n.t;
import { ref, onMounted, useTemplateRef } from 'vue';
import { Button, TableView, ProgressBar, InputDialog, FormGroup, TextInput, InputGroup, Switch, ButtonGroup, SingleSelect } from 'pankow';
import { Button, TableView, ProgressBar, InputDialog, Dialog, FormGroup, TextInput, InputGroup, Switch, ButtonGroup, SingleSelect } from 'pankow';
import { prettyDecimalSize } from 'pankow/utils';
import Section from '../components/Section.vue';
import SettingsItem from '../components/SettingsItem.vue';
@@ -29,14 +29,6 @@ const columns = {
const domains = ref([]);
const profile = ref({});
const busy = ref(true);
const mailboxSharingEnabled = ref(false);
const virtualAllMailEnabled = ref(false);
const ftsEnabled = ref(false);
const blocklist = ref([]);
const allowlist = ref([]);
const dnsblZones = ref([]);
const dnsblZonesString = ref('');
const spamCustomConfig = ref('');
async function refresh() {
busy.value = true;
@@ -147,6 +139,8 @@ async function onChangeMailDomain() {
locationChangeProgress.value = result.percent;
});
currentLocationDomain.value = locationDomain.value;
currentLocationSubdomain.value = locationSubdomain.value;
locationChangeBusy.value = false;
locationChangeMessage.value = '';
locationChangeProgress.value = 0;
@@ -167,6 +161,41 @@ async function onChangeMaxEmailSize() {
maxEmailSizeBusy.value = false;
}
const aclDialog = useTemplateRef('aclDialog');
const dnsblZonesError = ref('');
const dnsblZonesBusy = ref(false);
const dnsblZones = ref([]);
const dnsblZonesString = ref('');
function onShowAclDialog() {
dnsblZonesError.value = '';
dnsblZonesBusy.value = false;
aclDialog.value.open();
}
async function onSubmitAcl() {
dnsblZonesError.value = '';
dnsblZonesBusy.value = true;
const zones = dnsblZonesString.value.split('\n').filter((l) => { return l !== ''; });
const [error] = await mailModel.setDnsblConfig(zones);
if (error) {
dnsblZonesError.value = error.body ? error.body.message : 'Internal error';
dnsblZonesBusy.value = false;
return console.error(error);
}
aclDialog.value.close();
dnsblZones.value = zones;
dnsblZonesBusy.value = false;
}
const mailboxSharingEnabled = ref(false);
async function onChangeMailboxSharing(value) {
const [error] = await mailModel.setMailboxSharing(value);
if (error) {
@@ -175,6 +204,9 @@ async function onChangeMailboxSharing(value) {
}
}
const virtualAllMailEnabled = ref(false);
async function onChangeVirtualAllMail(value) {
const [error] = await mailModel.setVirtualAllMail(value);
if (error) {
@@ -183,6 +215,9 @@ async function onChangeVirtualAllMail(value) {
}
}
const ftsEnabled = ref(false);
async function onChangeFts(value) {
const [error] = await mailModel.setFtsConfig(value);
if (error) {
@@ -191,6 +226,49 @@ async function onChangeFts(value) {
}
}
const spamFilterDialog = useTemplateRef('spamFilterDialog');
const spamFilterBusy = ref(false);
const spamFilterError = ref('');
const blocklist = ref([]);
const allowlist = ref([]);
const spamCustomConfig = ref('');
function onShowSpamFilterDialog() {
spamFilterError.value = '';
spamFilterBusy.value = false;
spamFilterDialog.value.open();
}
async function onSubmitSpamFilter() {
spamFilterError.value = '';
spamFilterBusy.value = true;
const block = blocklist.value.split('\n').filter((l) => { return l !== ''; });
const allow = allowlist.value.split('\n').filter((l) => { return l !== ''; });
let [error] = await mailModel.setSpamAcl(allow, block);
if (error) {
spamFilterError.value = error.body ? error.body.message : 'Internal error';
spamFilterBusy.value = false;
return console.error(error);
}
[error] = await mailModel.setSpamCustomConfig(spamCustomConfig.value);
if (error) {
spamFilterError.value = error.body ? error.body.message : 'Internal error';
spamFilterBusy.value = false;
return console.error(error);
}
spamFilterDialog.value.close();
blocklist.value = block.join('\n');
allowlist.value = allow.join('\n');
spamFilterBusy.value = false;
}
onMounted(async () => {
let [error, result] = await profileModel.get();
if (error) return console.error(error);
@@ -220,8 +298,8 @@ onMounted(async () => {
[error, result] = await mailModel.dnsblConfig();
if (error) return console.error(error);
dnsblZones.value = result.join('\n');
dnsblZonesString.value = result;
dnsblZones.value = result;
dnsblZonesString.value = result.join('\n');
[error, result] = await mailModel.spamCustomConfig();
if (error) return console.error(error);
@@ -229,8 +307,8 @@ onMounted(async () => {
[error, result] = await mailModel.spamAcl();
if (error) return console.error(error);
allowlist.value = result.allowlist;
blocklist.value = result.blocklist;
allowlist.value = result.allowlist.join('\n');
blocklist.value = result.blocklist.join('\n');
[error, result] = await mailModel.ftsConfig();
if (error) return console.error(error);
@@ -245,6 +323,57 @@ onMounted(async () => {
<div class="content">
<InputDialog ref="inputDialog"/>
<Dialog ref="aclDialog"
:title="$t('emails.aclDialog.title')"
:reject-label="dnsblZonesBusy ? '' : $t('main.dialog.cancel')"
reject-style="secondary"
:confirm-label="$t('main.dialog.save')"
:confirm-busy="dnsblZonesBusy"
@confirm="onSubmitAcl()"
>
<form @submit.prevent="onSubmitAcl()" autocomplete="off">
<fieldset :disabled="dnsblZonesBusy">
<input type="submit" style="display: none"/>
<FormGroup>
<label for="dnsblZonesInput">{{ $t('emails.aclDialog.dnsblZones') }} <sup><a href="https://docs.cloudron.io/email/#dnsbl" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
<p class="small">{{ $t('emails.aclDialog.dnsblZonesInfo') }}</p>
<textarea id="dnsblZonesInput" v-model="dnsblZonesString" :placeholder="$t('emails.aclDialog.dnsblZonesPlaceholder')" rows="4"></textarea>
</FormGroup>
<div class="has-error" v-if="dnsblZonesError">{{ dnsblZonesError }}</div>
</fieldset>
</form>
</Dialog>
<Dialog ref="spamFilterDialog"
:title="$t('emails.spamFilterDialog.title')"
:reject-label="spamFilterBusy ? '' : $t('main.dialog.cancel')"
reject-style="secondary"
:confirm-label="$t('main.dialog.save')"
:confirm-busy="spamFilterBusy"
@confirm="onSubmitSpamFilter()"
>
<form @submit.prevent="onSubmitSpamFilter()" autocomplete="off">
<fieldset :disabled="spamFilterBusy">
<input type="submit" style="display: none"/>
<FormGroup>
<label for="blocklistInput">{{ $t('emails.spamFilterDialog.blacklisteAddresses') }}</label>
<p class="small">{{ $t('emails.spamFilterDialog.blacklisteAddressesInfo') }}</p>
<textarea id="blocklistInput" v-model="blocklist" :placeholder="$t('emails.spamFilterDialog.blacklisteAddressesPlaceholder')" rows="4"></textarea>
</FormGroup>
<FormGroup>
<label for="customConfigInput">{{ $t('emails.spamFilterDialog.customRules') }} <sup><a href="https://docs.cloudron.io/email/#custom-spam-filtering-rules" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
<textarea id="customConfigInput" v-model="spamCustomConfig" :placeholder="$t('emails.spamFilterDialog.customRulesPlaceholder')" rows="4"></textarea>
</FormGroup>
<div class="has-error" v-if="spamFilterError">{{ spamFilterError }}</div>
</fieldset>
</form>
</Dialog>
<h1 class="section-header">
{{ $t('emails.title') }}
<div style="display: flex; gap: 4px; flex-wrap: wrap; margin-top: 10px;">
@@ -301,7 +430,7 @@ onMounted(async () => {
</div>
<template #bottom v-if="locationChangeProgress">
<ProgressBar :value="locationChangeProgress"/>
{{ locationChangeMessage }}
<div style="padding-top: 6px">{{ locationChangeMessage }}</div>
</template>
</SettingsItem>
@@ -347,7 +476,7 @@ onMounted(async () => {
<div>{{ $t('emails.settings.aclOverview', { dnsblZonesCount: dnsblZones.length }) }}</div>
</FormGroup>
<div style="display: flex; align-items: center">
<Button tool plain>Edit</Button>
<Button tool plain @click="onShowAclDialog()">Edit</Button>
</div>
</SettingsItem>
@@ -357,7 +486,7 @@ onMounted(async () => {
<div>{{ $t('emails.settings.spamFilterOverview', { blacklistCount: blocklist.length }) }}</div>
</FormGroup>
<div style="display: flex; align-items: center">
<Button tool plain>Edit</Button>
<Button tool plain @click="onShowSpamFilterDialog()">Edit</Button>
</div>
</SettingsItem>