feat(mail): abgeschlossene E-Mails erneut zur Bearbeitung freigeben
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
Build and Push Multi-Platform Images / build-and-push (push) Successful in 39s
Der Import-Wizard ist für verarbeitete E-Mails gesperrt. Damit ließ sich
ein fehlerhaft abgeschlossener Vorgang bisher nicht korrigieren.
Administratoren können eine E-Mail in der Detailansicht nun wieder
freigeben (POST /api/emails/:id/reimport, MANAGE_ALL). Die Anhänge aus
der Datenbank werden weiterverwendet; ein erneuter Abruf vom IMAP-Server
findet nicht statt.
Die Freigabe setzt Status 4 ("Zur Nachbearbeitung") statt Status 0:
check-attachments prüft Mails mit Status 0, findet die Anhänge per
Checksumme in Paperless – dort liegen sie ja bereits – und würde die
Freigabe beim nächsten Lauf sofort wieder auf "Verarbeitet" zurückdrehen.
Status 4 bleibt davon unberührt. Da Status ein freies int ist, ist dafür
keine Migration nötig.
Erlaubt sind nur die Status 1, 2 und 3; liegt die E-Mail ohnehin im
Arbeitsvorrat, antwortet der Endpunkt mit 400, statt den Zustand still zu
überschreiben. Wer die Freigabe ausgelöst hat, steht im Log.
Der neue Status erscheint als eigener Tag sowie in beiden Filtern der
Mailpostfach-Übersicht, damit die freigegebenen Mails auffindbar bleiben.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,4 +48,8 @@ export const emailsApi = {
|
||||
|
||||
updateStatus: (id: number, status: number) =>
|
||||
api.patch<{ message?: string }>(`/api/emails/${id}/status`, { status }).then((r) => r.data),
|
||||
|
||||
// Gibt eine bereits abgeschlossene E-Mail wieder zur Bearbeitung frei (nur Admins).
|
||||
reimport: (id: number) =>
|
||||
api.post<EmailItem>(`/api/emails/${id}/reimport`).then((r) => r.data),
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useParams, useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Card, Button, Space, Spin, Tag, Typography, Table, message, Empty, Popconfirm, theme
|
||||
} from 'antd';
|
||||
import { ArrowLeftOutlined, FileTextOutlined, CloseCircleOutlined, LinkOutlined } from '@ant-design/icons';
|
||||
import { ArrowLeftOutlined, FileTextOutlined, CloseCircleOutlined, LinkOutlined, RedoOutlined } from '@ant-design/icons';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import dayjs from 'dayjs';
|
||||
import { emailsApi, type EmailItem, type EmailAttachment } from '../api/emails';
|
||||
@@ -11,6 +11,8 @@ import { emailImportApi } from '../api/email-import';
|
||||
import { getEnv } from '../utils/env';
|
||||
import MailImportWizard from '../components/MailImportWizard';
|
||||
import { useIsMobile } from '../hooks/useIsMobile';
|
||||
import { useAuth } from '../auth/AuthContext';
|
||||
import { Permission } from '../auth/permissions';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
@@ -25,7 +27,9 @@ export default function MailDetailPage() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [previewLoading, setPreviewLoading] = useState(false);
|
||||
const [wizardOpen, setWizardOpen] = useState(false);
|
||||
const [reimporting, setReimporting] = useState(false);
|
||||
const { token } = theme.useToken();
|
||||
const { hasPermission } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) return;
|
||||
@@ -51,6 +55,22 @@ export default function MailDetailPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// Gibt eine abgeschlossene E-Mail wieder zur Bearbeitung frei (Status 4).
|
||||
// Danach ist der Import-Wizard erneut nutzbar.
|
||||
const handleReimport = async () => {
|
||||
if (!email) return;
|
||||
setReimporting(true);
|
||||
try {
|
||||
const updated = await emailsApi.reimport(email.Id);
|
||||
setEmail(updated);
|
||||
message.success('E-Mail wurde zur Nachbearbeitung freigegeben');
|
||||
} catch {
|
||||
message.error('Fehler beim Freigeben der E-Mail');
|
||||
} finally {
|
||||
setReimporting(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!selected) {
|
||||
setPreviewUrl(null);
|
||||
@@ -148,6 +168,20 @@ export default function MailDetailPage() {
|
||||
</Space>
|
||||
|
||||
<Space wrap>
|
||||
{hasPermission(Permission.MANAGE_ALL) && email.Status !== 0 && email.Status !== 4 && (
|
||||
<Popconfirm
|
||||
title="Erneut importieren"
|
||||
description="Diese E-Mail wurde bereits abgeschlossen. Möchten Sie sie wieder zur Bearbeitung freigeben?"
|
||||
onConfirm={handleReimport}
|
||||
okText="Ja"
|
||||
cancelText="Nein"
|
||||
placement="bottomRight"
|
||||
>
|
||||
<Button icon={<RedoOutlined />} loading={reimporting}>
|
||||
Erneut importieren
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
<Popconfirm
|
||||
title="E-Mail ignorieren"
|
||||
description="Möchten Sie diese E-Mail wirklich als ignoriert markieren?"
|
||||
|
||||
@@ -17,6 +17,7 @@ function renderStatusTag(s: number) {
|
||||
if (s === 1) return <Tag color="green">Verarbeitet</Tag>;
|
||||
if (s === 2) return <Tag color="red">Fehler</Tag>;
|
||||
if (s === 3) return <Tag color="default">Ignoriert</Tag>;
|
||||
if (s === 4) return <Tag color="orange">Zur Nachbearbeitung</Tag>;
|
||||
return <Tag>{s}</Tag>;
|
||||
}
|
||||
|
||||
@@ -101,6 +102,7 @@ export default function MailpostfachPage() {
|
||||
{ text: 'Verarbeitet', value: 1 },
|
||||
{ text: 'Fehler', value: 2 },
|
||||
{ text: 'Ignoriert', value: 3 },
|
||||
{ text: 'Zur Nachbearbeitung', value: 4 },
|
||||
],
|
||||
onFilter: (value, record) => record.Status === value,
|
||||
},
|
||||
@@ -216,6 +218,7 @@ export default function MailpostfachPage() {
|
||||
{ value: 1, label: 'Verarbeitet' },
|
||||
{ value: 2, label: 'Fehler' },
|
||||
{ value: 3, label: 'Ignoriert' },
|
||||
{ value: 4, label: 'Zur Nachbearbeitung' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user