added backup and email client

This commit is contained in:
2026-02-01 00:02:35 +01:00
parent ff857be01a
commit e4fdfbc95f
210 changed files with 24211 additions and 742 deletions
+279 -2
View File
@@ -216,16 +216,95 @@ export interface StressfreiEmail {
platform?: string;
notes?: string;
isActive: boolean;
hasMailbox: boolean;
createdAt: string;
updatedAt: string;
}
// Mailbox-Konto (für Dropdown-Auswahl)
export interface MailboxAccount {
id: number;
email: string;
notes?: string;
hasMailbox: boolean;
_count: {
cachedEmails: number;
};
}
// Gecachte E-Mail
export interface CachedEmail {
id: number;
stressfreiEmailId: number;
folder: 'INBOX' | 'SENT';
messageId: string;
uid: number;
subject?: string;
fromAddress: string;
fromName?: string;
toAddresses: string; // JSON Array
ccAddresses?: string; // JSON Array
receivedAt: string;
textBody?: string;
htmlBody?: string;
hasAttachments: boolean;
attachmentNames?: string; // JSON Array
contractId?: number;
assignedAt?: string;
assignedBy?: number;
isAutoAssigned?: boolean; // true = automatisch beim Senden aus Vertrag zugeordnet
isRead: boolean;
isStarred: boolean;
isDeleted: boolean;
deletedAt?: string;
createdAt: string;
updatedAt: string;
stressfreiEmail?: {
id: number;
email: string;
customerId: number;
};
contract?: {
id: number;
contractNumber: string;
} | null;
}
export interface SyncResult {
newEmails: number;
totalEmails: number;
}
export interface EmailAttachment {
filename: string;
content: string; // Base64-kodierter Inhalt
contentType?: string; // MIME-Type (z.B. 'application/pdf')
}
export interface SendEmailParams {
to: string | string[];
cc?: string | string[];
subject: string;
text?: string;
html?: string;
inReplyTo?: string;
references?: string[];
attachments?: EmailAttachment[];
contractId?: number; // Vertrag dem die gesendete E-Mail zugeordnet wird
}
export const stressfreiEmailApi = {
getByCustomer: async (customerId: number, includeInactive = false) => {
const res = await api.get<ApiResponse<StressfreiEmail[]>>(`/customers/${customerId}/stressfrei-emails`, { params: { includeInactive } });
return res.data;
},
create: async (customerId: number, data: { email: string; platform?: string; notes?: string }) => {
create: async (customerId: number, data: {
email: string;
platform?: string;
notes?: string;
provisionAtProvider?: boolean;
createMailbox?: boolean;
}) => {
const res = await api.post<ApiResponse<StressfreiEmail>>(`/customers/${customerId}/stressfrei-emails`, data);
return res.data;
},
@@ -237,6 +316,150 @@ export const stressfreiEmailApi = {
const res = await api.delete<ApiResponse<void>>(`/stressfrei-emails/${id}`);
return res.data;
},
// Mailbox nachträglich aktivieren
enableMailbox: async (id: number) => {
const res = await api.post<ApiResponse<null>>(`/stressfrei-emails/${id}/enable-mailbox`);
return res.data;
},
// Mailbox-Status mit Provider synchronisieren
syncMailboxStatus: async (id: number) => {
const res = await api.post<ApiResponse<{ hasMailbox: boolean; wasUpdated: boolean }>>(`/stressfrei-emails/${id}/sync-mailbox-status`);
return res.data;
},
// Mailbox-Zugangsdaten abrufen (IMAP/SMTP)
getMailboxCredentials: async (id: number) => {
const res = await api.get<ApiResponse<{
email: string;
password: string;
imap: { server: string; port: number; encryption: string } | null;
smtp: { server: string; port: number; encryption: string } | null;
}>>(`/stressfrei-emails/${id}/credentials`);
return res.data;
},
// Passwort zurücksetzen (generiert neues Passwort beim Provider)
resetPassword: async (id: number) => {
const res = await api.post<ApiResponse<{ password: string }>>(`/stressfrei-emails/${id}/reset-password`);
return res.data;
},
// E-Mails synchronisieren
syncEmails: async (id: number, fullSync = false) => {
const res = await api.post<ApiResponse<SyncResult>>(`/stressfrei-emails/${id}/sync`, {}, { params: { full: fullSync } });
return res.data;
},
// E-Mail senden
sendEmail: async (id: number, params: SendEmailParams) => {
const res = await api.post<ApiResponse<{ messageId: string }>>(`/stressfrei-emails/${id}/send`, params);
return res.data;
},
// Ordner-Anzahlen abrufen (total und ungelesen pro Ordner)
getFolderCounts: async (id: number) => {
const res = await api.get<ApiResponse<{
inbox: number;
inboxUnread: number;
sent: number;
sentUnread: number;
trash: number;
trashUnread: number;
}>>(`/stressfrei-emails/${id}/folder-counts`);
return res.data;
},
};
// Cached Email API (E-Mail-Client)
export const cachedEmailApi = {
// E-Mails für Kunden abrufen
getForCustomer: async (customerId: number, options?: { accountId?: number; folder?: 'INBOX' | 'SENT'; limit?: number; offset?: number }) => {
const res = await api.get<ApiResponse<CachedEmail[]>>(`/customers/${customerId}/emails`, { params: options });
return res.data;
},
// E-Mails für Vertrag abrufen
getForContract: async (contractId: number, options?: { folder?: 'INBOX' | 'SENT'; limit?: number; offset?: number }) => {
const res = await api.get<ApiResponse<CachedEmail[]>>(`/contracts/${contractId}/emails`, { params: options });
return res.data;
},
// Ordner-Anzahlen für Vertrag abrufen (zugeordnete E-Mails)
getContractFolderCounts: async (contractId: number) => {
const res = await api.get<ApiResponse<{
inbox: number;
inboxUnread: number;
sent: number;
sentUnread: number;
}>>(`/contracts/${contractId}/emails/folder-counts`);
return res.data;
},
// Mailbox-Konten eines Kunden abrufen
getMailboxAccounts: async (customerId: number) => {
const res = await api.get<ApiResponse<MailboxAccount[]>>(`/customers/${customerId}/mailbox-accounts`);
return res.data;
},
// Einzelne E-Mail abrufen (mit Body)
getById: async (id: number) => {
const res = await api.get<ApiResponse<CachedEmail>>(`/emails/${id}`);
return res.data;
},
// E-Mail-Thread abrufen
getThread: async (id: number) => {
const res = await api.get<ApiResponse<CachedEmail[]>>(`/emails/${id}/thread`);
return res.data;
},
// Als gelesen/ungelesen markieren
markAsRead: async (id: number, isRead: boolean) => {
const res = await api.patch<ApiResponse<void>>(`/emails/${id}/read`, { isRead });
return res.data;
},
// Stern umschalten
toggleStar: async (id: number) => {
const res = await api.post<ApiResponse<{ isStarred: boolean }>>(`/emails/${id}/star`);
return res.data;
},
// Vertrag zuordnen
assignToContract: async (emailId: number, contractId: number) => {
const res = await api.post<ApiResponse<CachedEmail>>(`/emails/${emailId}/assign`, { contractId });
return res.data;
},
// Zuordnung aufheben
unassignFromContract: async (emailId: number) => {
const res = await api.delete<ApiResponse<CachedEmail>>(`/emails/${emailId}/assign`);
return res.data;
},
// E-Mail löschen (nur Admin)
delete: async (emailId: number) => {
const res = await api.delete<ApiResponse<void>>(`/emails/${emailId}`);
return res.data;
},
// Anhang-URL (view=true für inline anzeigen, sonst download)
getAttachmentUrl: (emailId: number, filename: string, view?: boolean) => {
const token = localStorage.getItem('token');
const encodedFilename = encodeURIComponent(filename);
const viewParam = view ? '&view=true' : '';
return `${api.defaults.baseURL}/emails/${emailId}/attachments/${encodedFilename}?token=${token}${viewParam}`;
},
// Ungelesene E-Mails zählen
getUnreadCount: async (params: { customerId?: number; contractId?: number }) => {
const res = await api.get<ApiResponse<{ count: number }>>('/emails/unread-count', { params });
return res.data;
},
// ==================== PAPIERKORB ====================
// Papierkorb-E-Mails für Kunden abrufen
getTrash: async (customerId: number) => {
const res = await api.get<ApiResponse<CachedEmail[]>>(`/customers/${customerId}/emails/trash`);
return res.data;
},
// Papierkorb-Anzahl für Kunden
getTrashCount: async (customerId: number) => {
const res = await api.get<ApiResponse<{ count: number }>>(`/customers/${customerId}/emails/trash/count`);
return res.data;
},
// E-Mail aus Papierkorb wiederherstellen
restore: async (emailId: number) => {
const res = await api.post<ApiResponse<void>>(`/emails/${emailId}/restore`);
return res.data;
},
// E-Mail endgültig löschen (aus Papierkorb)
permanentDelete: async (emailId: number) => {
const res = await api.delete<ApiResponse<void>>(`/emails/${emailId}/permanent`);
return res.data;
},
};
// Contracts
@@ -378,6 +601,51 @@ export const appSettingsApi = {
},
};
// Backup & Restore
export interface BackupInfo {
name: string;
timestamp: string;
totalRecords: number;
tables: { table: string; count: number }[];
sizeBytes: number;
hasUploads: boolean;
uploadSizeBytes: number;
}
export const backupApi = {
list: async () => {
const res = await api.get<ApiResponse<BackupInfo[]>>('/settings/backups');
return res.data;
},
create: async () => {
const res = await api.post<ApiResponse<{ backupName: string }>>('/settings/backup');
return res.data;
},
restore: async (name: string) => {
const res = await api.post<ApiResponse<{ restoredRecords: number; restoredFiles: number }>>(`/settings/backup/${name}/restore`);
return res.data;
},
delete: async (name: string) => {
const res = await api.delete<ApiResponse<void>>(`/settings/backup/${name}`);
return res.data;
},
getDownloadUrl: (name: string) => {
return `/api/settings/backup/${name}/download`;
},
upload: async (file: File) => {
const formData = new FormData();
formData.append('backup', file);
const res = await api.post<ApiResponse<{ backupName: string }>>('/settings/backup/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return res.data;
},
factoryReset: async () => {
const res = await api.post<ApiResponse<void>>('/settings/factory-reset');
return res.data;
},
};
// Platforms
export const platformApi = {
getAll: async (includeInactive = false) => {
@@ -645,7 +913,7 @@ export const userApi = {
const res = await api.get<ApiResponse<User>>(`/users/${id}`);
return res.data;
},
create: async (data: { email: string; password: string; firstName: string; lastName: string; roleIds: number[]; customerId?: number }) => {
create: async (data: { email: string; password: string; firstName: string; lastName: string; roleIds: number[]; customerId?: number; hasDeveloperAccess?: boolean }) => {
const res = await api.post<ApiResponse<User>>('/users', data);
return res.data;
},
@@ -698,6 +966,15 @@ export interface EmailProviderConfig {
passwordEncrypted?: string;
domain: string;
defaultForwardEmail?: string;
// IMAP/SMTP-Server (für E-Mail-Client)
imapServer?: string;
imapPort?: number;
smtpServer?: string;
smtpPort?: number;
// Verschlüsselungs-Einstellungen
imapEncryption?: 'SSL' | 'STARTTLS' | 'NONE';
smtpEncryption?: 'SSL' | 'STARTTLS' | 'NONE';
allowSelfSignedCerts?: boolean; // Selbstsignierte Zertifikate erlauben
isActive: boolean;
isDefault: boolean;
createdAt: string;