Skip to content

Commit

Permalink
Merge pull request #3205 from modoboa/feature/postfix_autoreply
Browse files Browse the repository at this point in the history
Postfix autoreply merged back to core repo
  • Loading branch information
tonioo committed Mar 20, 2024
2 parents e4ef7e0 + 415dce1 commit ba8f457
Show file tree
Hide file tree
Showing 98 changed files with 40,585 additions and 25,867 deletions.
Binary file modified doc/_static/modoboa_logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions doc/configuration.rst
Expand Up @@ -644,3 +644,31 @@ Hash the file using the following command::
Finally, reload postfix::

$ service postfix reload

************************
Auto-reply using Postfix
************************

The user that executes the autoreply script needs to access
:file:`settings.py`. You must apply proper permissions on this file. For
example, if :file:`settings.py` belongs to ``www-data:www-data``, you can add
the ``vmail`` user to the ``www-data`` group and set the read permission
for the group.

To make Postfix use this feature, you need to update your
configuration file as follows:

``/etc/postfix/master.cf``::

autoreply unix - n n - - pipe
flags= user=vmail:<group> argv=python <modoboa_site>/manage.py autoreply $sender $mailbox

Replace ``<driver>`` by the name of the database you
use. ``<modoboa_site>`` is the path of your Modoboa instance.

.. note::

Auto-reply messages are just sent once per sender for a
pre-defined time period. By default, this period is equal to 1 day
(86400s), you can adjust this value by modifying the **Automatic
reply timeout** parameter available in the online panel.
3 changes: 0 additions & 3 deletions doc/index.rst
Expand Up @@ -32,9 +32,6 @@ And it is extensible by nature and comes with a lot of additional extensions:
|`modoboa-pfxadmin-migrate |A tool to migrate from |https://github.com/modoboa/modoboa-pfxadmin-migrate |
|<https://github.com/modoboa/modoboa-pfxadmin-migrate>`_ |Postfixadmin | |
+---------------------------------------------------------+-------------------------+------------------------------------------------------+
|`modoboa-postfix-autoreply |Away message editor |https://modoboa-postfix-autoreply.readthedocs.io |
|<https://github.com/modoboa/modoboa-postfix-autoreply>`_ |(postfix compatible) | |
+---------------------------------------------------------+-------------------------+------------------------------------------------------+
|`modoboa-radicale |A frontend for `Radicale |https://modoboa-radicale.readthedocs.io |
|<https://github.com/modoboa/modoboa-radicale>`_ |<http://radicale.org>`_ | |
+---------------------------------------------------------+-------------------------+------------------------------------------------------+
Expand Down
41 changes: 41 additions & 0 deletions doc/upgrade.rst
Expand Up @@ -131,6 +131,47 @@ Rebuild Virtual Environment
Specific instructions
*********************

2.3.0
=====

.. warning::

For this particular version, it is really important that you apply
new migrations **AFTER** the following instructions. If you don't,
you'll get into trouble...

The ``modoboa-postfix-autoreply`` plugin has been merged into the core.

In :file:`settings.py` file, add ``'modoboa.postfix_autoreply'`` 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',
'modoboa.pdfcredentials',
'modoboa.imap_migration',
'modoboa.postfix_autoreply',
)

And remove any reference to ``'modoboa_postfix_autoreply'`` in this same variable.

After upgrading modoboa, run the following commands from your virtual environment:

.. sourcecode:: bash

> python manage.py rename_app modoboa_postfix_autoreply postfix_autoreply


2.2.3
=====
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/api/account.js
Expand Up @@ -44,4 +44,10 @@ export default {
deleteAPIToken() {
return repository.delete(`${resource}/api_token/`)
},
getARMessage() {
return repository.get(`${resource}/armessage/`)
},
setARMessage(data) {
return repository.put(`${resource}/armessage/`, data)
},
}
118 changes: 118 additions & 0 deletions frontend/src/components/account/APISetupForm.vue
@@ -0,0 +1,118 @@
<template>
<v-card v-if="!token" flat>
<v-card-text>
{{ $gettext('Your API token has not been generated yet.') }}
</v-card-text>
<v-card-actions>
<v-btn
color="success"
variant="flat"
:loading="loading"
@click="generateKey"
>
{{ $gettext('Generate') }}
</v-btn>
</v-card-actions>
</v-card>
<v-card v-else flat>
<v-card-text>
<label class="m-label">
{{ $gettext('Your API token is:') }}
</label>
<code class="ml-5 mr-5">
{{ token }}
</code>
<v-btn
icon="mdi-clipboard-plus"
density="compact"
:title="$gettext('Copy token to clipboard')"
variant="text"
@click="copyToClipboard()"
>
</v-btn>
<v-btn
icon="mdi-delete"
density="compact"
color="error"
variant="text"
:title="$gettext('Delete token')"
@click="openDeletionDialog"
>
</v-btn>
</v-card-text>
</v-card>
<v-alert type="info" variant="tonal" border="start" class="mt-4">
{{ $gettext('A documentation of the API is available') }}
<a :href="apiDocUrl" target="_blank">{{ $gettext('here') }}</a
>.
</v-alert>
<ConfirmDialog ref="confirm" @agree="deleteToken" />
</template>

<script setup>
import accountApi from '@/api/account'
import { useBusStore } from '@/stores'
import ConfirmDialog from '@/components/tools/ConfirmDialog.vue'
import { ref, computed, inject, onMounted } from 'vue'
import { useGettext } from 'vue3-gettext'
const { $gettext } = useGettext()
const busStore = useBusStore()
const $config = inject('$config')
const apiDocUrl = computed(() => $config.API_DOC_URL)
const loading = ref(false)
const token = ref(null)
const confirm = ref()
function copyToClipboard() {
navigator.clipboard.writeText(token.value)
busStore.displayNotification({
msg: $gettext('API token copied to your clipboard'),
type: 'success',
})
}
function generateKey() {
loading.value = true
accountApi
.createAPIToken()
.then((resp) => {
token.value = resp.data.token
busStore.displayNotification({
msg: $gettext('API token created'),
type: 'success',
})
})
.finally(() => (loading.value = false))
}
function openDeletionDialog() {
confirm.value.open(
$gettext('Warning'),
$gettext('You are about to delete your API access token'),
{
color: 'error',
cancelLabel: $gettext('Cancel'),
agreeLabel: $gettext('Proceed'),
}
)
}
async function deleteToken() {
await accountApi.deleteAPIToken()
busStore.displayNotification({
msg: $gettext('API token deleted'),
type: 'success',
})
token.value = null
}
onMounted(() => {
accountApi.getAPIToken().then((resp) => {
token.value = resp.data.token
})
})
</script>
98 changes: 98 additions & 0 deletions frontend/src/components/account/AutoReplyForm.vue
@@ -0,0 +1,98 @@
<template>
<v-card flat>
<v-card-text>
<v-form ref="formRef" @submit.prevent="submit">
<v-checkbox
v-model="form.enabled"
:label="$gettext('Enabled')"
color="primary"
hide-details
class="mb-4"
/>
<label class="m-label">{{ $gettext('Subject') }}</label>
<v-text-field
v-model="form.subject"
variant="outlined"
density="compact"
:rules="[rules.required]"
/>
<div class="mb-4">
<label class="m-label">{{ $gettext('Content') }}</label>
<v-textarea
v-model="form.content"
:hint="$gettext('The content of your answer. You can use the following variables, which will be automatically replaced by the appropriate value: %(name)s, %(fromdate)s, %(untildate)s')"
persistent-hint
variant="outlined"
rows="3"
density="compact"
:rules="[rules.required]"
/>
</div>
<div class="mb-4">
<label class="m-label">{{ $gettext('From') }}</label>
<v-text-field
v-model="form.fromdate"
:hint="$gettext('Activate your auto reply from this date')"
variant="outlined"
persistent-hint
type="datetime-local"
density="compact"
/>
</div>
<div class="mb-4">
<label class="m-label">{{ $gettext('Until') }}</label>
<v-text-field
v-model="form.untildate"
:hint="$gettext('Activate your auto reply until this date')"
variant="outlined"
persistent-hint
type="datetime-local"
density="compact"
/>
</div>
<v-btn color="success" type="submit" :loading="loading">
{{ $gettext('Update auto-reply') }}
</v-btn>
</v-form>
</v-card-text>
</v-card>
</template>

<script setup>
import { ref } from 'vue'
import { useBusStore } from '@/stores'
import { useGettext } from 'vue3-gettext'
import accountApi from '@/api/account'
import rules from '@/plugins/rules'
const busStore = useBusStore()
const { $gettext } = useGettext()
const form = ref({})
const formRef = ref()
const loading = ref(false)
async function submit() {
const { valid } = await formRef.value.validate()
if (!valid) {
return
}
loading.value = true
accountApi.setARMessage(form.value).then(() => {
busStore.displayNotification({ msg: $gettext('Auto-reply message updated') })
loading.value = false
}).catch(() => {
loading.value = false
})
}
accountApi.getARMessage().then(resp => {
form.value = resp.data
if (form.value.fromdate) {
form.value.fromdate = form.value.fromdate.slice(0, -4)
}
if (form.value.untildate) {
form.value.untildate = form.value.untildate.slice(0, -4)
}
})
</script>
@@ -1,4 +1,3 @@
Ac
<template>
<v-card>
<v-card-title>
Expand Down Expand Up @@ -57,11 +56,12 @@ Ac
</template>

<script setup lang="js">
// import { bus } from '@/main'
import { ref } from 'vue'
import { useGettext } from 'vue3-gettext'
import { useBusStore } from '@/stores'
import senderAddresses from '@/api/senderAddresses'
const busStore = useBusStore()
const { $gettext } = useGettext()
const props = defineProps({ account: { type: Object, default: null } })
Expand Down Expand Up @@ -94,14 +94,14 @@ function submit() {
fetchSenderAddresses()
newAddress.value = null
hideAddBtn.value = false
// bus.$emit('notification', { msg: this.$gettext('Sender address added') })
busStore.displayNotification({ msg: $gettext('Sender address added') })
})
}
function deleteSenderAddress(senderAddress) {
senderAddresses.delete(senderAddress.pk).then(() => {
fetchSenderAddresses()
// bus.$emit('notification', { msg: this.$gettext('Sender address deleted') })
busStore.displayNotification({ msg: $gettext('Sender address deleted') })
})
}
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/components/login/LoginForm.vue
Expand Up @@ -33,7 +33,11 @@ async function authenticate() {
authStore
.login(payload)
.then(() => {
router.push({ name: 'Dashboard' })
if (authStore.authUser.role === 'SimpleUsers') {
router.push({ name: 'AccountSettings' })
} else {
router.push({ name: 'Dashboard' })
}
})
.catch((err) => {
loading.value = false
Expand Down

0 comments on commit ba8f457

Please sign in to comment.