174 lines
5.9 KiB
TypeScript
174 lines
5.9 KiB
TypeScript
import { Injectable } from "@nestjs/common";
|
|
import { Observable } from "rxjs";
|
|
import { catchError, map, throwError } from "rxjs";
|
|
|
|
import { WildDuckBaseService } from "./wildduck-base.service";
|
|
import { MailServerException } from "../../../core/exceptions/mail-server.exceptions";
|
|
import { ListMessagesQueryDto, SearchMessagesQueryDto, UpdateMessageDto, UploadMessageDto } from "../DTO/message.dto";
|
|
import { AttachmentResponse } from "../interfaces/attachment.interface";
|
|
import {
|
|
MessageDeleteAllResponse,
|
|
MessageDetails,
|
|
MessageEventsResponse,
|
|
MessageFlaggedResponse,
|
|
MessageForwardResponse,
|
|
MessageListResponse,
|
|
MessageSearchResponse,
|
|
MessageSubmitResponse,
|
|
MessageUpdateResponse,
|
|
MessageUploadResponse,
|
|
} from "../interfaces/messages-response.interface";
|
|
import { WildDuckSuccessResponse } from "../interfaces/wildduck-response.interface";
|
|
|
|
@Injectable()
|
|
export class WildDuckMessagesService extends WildDuckBaseService {
|
|
/**
|
|
* List messages in a mailbox
|
|
*/
|
|
listMessages(userId: string, mailboxId: string, query?: ListMessagesQueryDto): Observable<MessageListResponse> {
|
|
return this.get<MessageListResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages`, query);
|
|
}
|
|
|
|
/**
|
|
* Get message details
|
|
*/
|
|
getMessage(userId: string, mailboxId: string, messageId: number): Observable<MessageDetails> {
|
|
return this.get<MessageDetails>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}`);
|
|
}
|
|
|
|
/**
|
|
* Update message details
|
|
*/
|
|
updateMessage(userId: string, mailboxId: string, messageId: number | string, data: UpdateMessageDto): Observable<MessageUpdateResponse> {
|
|
return this.put<MessageUpdateResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}`, data);
|
|
}
|
|
|
|
/**
|
|
* Delete a message
|
|
*/
|
|
deleteMessage(userId: string, mailboxId: string, messageId: number): Observable<WildDuckSuccessResponse> {
|
|
return this.delete<WildDuckSuccessResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}`);
|
|
}
|
|
|
|
/**
|
|
* Delete all messages from a mailbox
|
|
*/
|
|
deleteAllFromMailbox(userId: string, mailboxId: string): Observable<MessageDeleteAllResponse> {
|
|
return this.delete<MessageDeleteAllResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages`);
|
|
}
|
|
|
|
/**
|
|
* Upload message to mailbox
|
|
*/
|
|
uploadMessage(userId: string, mailboxId: string, data: UploadMessageDto): Observable<MessageUploadResponse> {
|
|
return this.post<MessageUploadResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages`, data);
|
|
}
|
|
|
|
/**
|
|
* Get message source (raw email)
|
|
*/
|
|
getMessageSource(userId: string, mailboxId: string, messageId: number): Observable<string> {
|
|
// This returns raw email content, not JSON
|
|
return this.get<string>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/message.eml`);
|
|
}
|
|
|
|
/**
|
|
* Get message attachment
|
|
*/
|
|
getMessageAttachment(userId: string, mailboxId: string, messageId: number, attachmentId: string): Observable<AttachmentResponse> {
|
|
// This returns binary content
|
|
const url = this.buildUrl(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/attachments/${attachmentId}`);
|
|
this.logger.debug(`WildDuck GET: ${url}`);
|
|
|
|
return this.httpService
|
|
.get(url, {
|
|
responseType: "stream",
|
|
headers: {
|
|
Accept: "*/*",
|
|
},
|
|
})
|
|
.pipe(
|
|
map((response) => {
|
|
this.logger.debug(`HTTP ${response.status}: ${response.config?.url}`);
|
|
return {
|
|
success: response.data,
|
|
headers: response.headers,
|
|
contentType: response.headers["content-type"],
|
|
contentDisposition: response.headers["content-disposition"],
|
|
contentLength: response.headers["content-length"],
|
|
} as AttachmentResponse;
|
|
}),
|
|
catchError((error) => {
|
|
this.logger.error(`WildDuck API error: ${error.message}`, error.stack);
|
|
|
|
if (error.response?.data?.error) {
|
|
return throwError(() => new MailServerException(error.response.data.error));
|
|
}
|
|
|
|
return throwError(() => error);
|
|
}),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get message events/timeline
|
|
*/
|
|
getMessageEvents(userId: string, mailboxId: string, messageId: number): Observable<MessageEventsResponse> {
|
|
return this.get<MessageEventsResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/events`);
|
|
}
|
|
|
|
/**
|
|
* List flagged messages across all mailboxes
|
|
*/
|
|
listFlaggedMessages(userId: string, query?: { order?: "asc" | "desc"; limit?: number; page?: number }): Observable<MessageFlaggedResponse> {
|
|
return this.get<MessageFlaggedResponse>(`/users/${userId}/flagged`, query);
|
|
}
|
|
|
|
/**
|
|
* Search for messages across all mailboxes
|
|
*/
|
|
searchMessages(userId: string, query: SearchMessagesQueryDto): Observable<MessageSearchResponse> {
|
|
return this.get<MessageSearchResponse>(`/users/${userId}/search`, query);
|
|
}
|
|
|
|
/**
|
|
* Delete all messages from a mailbox
|
|
*/
|
|
deleteAllMessages(userId: string, mailboxId: string): Observable<MessageDeleteAllResponse> {
|
|
return this.delete<MessageDeleteAllResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages`);
|
|
}
|
|
|
|
/**
|
|
* Forward stored message
|
|
*/
|
|
forwardMessage(
|
|
userId: string,
|
|
mailboxId: string,
|
|
messageId: number,
|
|
data: {
|
|
target: number;
|
|
addresses: string[];
|
|
sess?: string;
|
|
ip?: string;
|
|
},
|
|
): Observable<MessageForwardResponse> {
|
|
return this.post<MessageForwardResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/forward`, data);
|
|
}
|
|
|
|
/**
|
|
* Submit draft for delivery
|
|
*/
|
|
submitDraft(
|
|
userId: string,
|
|
mailboxId: string,
|
|
messageId: number,
|
|
data?: {
|
|
deleteFiles?: boolean;
|
|
sess?: string;
|
|
ip?: string;
|
|
},
|
|
): Observable<MessageSubmitResponse> {
|
|
return this.post<MessageSubmitResponse>(`/users/${userId}/mailboxes/${mailboxId}/messages/${messageId}/submit`, data);
|
|
}
|
|
}
|