Initial commit
This commit is contained in:
376
src/models/message.ts
Normal file
376
src/models/message.ts
Normal file
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* Message and MessagePart model classes
|
||||
*/
|
||||
|
||||
import type { MessageInterface, MessagePartInterface } from "@/types/message";
|
||||
|
||||
/**
|
||||
* MessagePart class for working with message body parts
|
||||
*/
|
||||
export class MessagePartObject {
|
||||
|
||||
_data: MessagePartInterface;
|
||||
|
||||
constructor(data?: Partial<MessagePartInterface>) {
|
||||
this._data = {
|
||||
partId: data?.partId ?? null,
|
||||
blobId: data?.blobId ?? null,
|
||||
size: data?.size ?? null,
|
||||
name: data?.name ?? null,
|
||||
type: data?.type ?? undefined,
|
||||
charset: data?.charset ?? null,
|
||||
disposition: data?.disposition ?? null,
|
||||
cid: data?.cid ?? null,
|
||||
language: data?.language ?? null,
|
||||
location: data?.location ?? null,
|
||||
content: data?.content ?? undefined,
|
||||
subParts: data?.subParts ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
fromJson(data: MessagePartInterface): MessagePartObject {
|
||||
this._data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
toJson(): MessagePartInterface {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
clone(): MessagePartObject {
|
||||
return new MessagePartObject(JSON.parse(JSON.stringify(this._data)));
|
||||
}
|
||||
|
||||
/** Properties */
|
||||
|
||||
get partId(): string | null | undefined {
|
||||
return this._data.partId;
|
||||
}
|
||||
|
||||
get blobId(): string | null | undefined {
|
||||
return this._data.blobId;
|
||||
}
|
||||
|
||||
get size(): number | null | undefined {
|
||||
return this._data.size;
|
||||
}
|
||||
|
||||
get name(): string | null | undefined {
|
||||
return this._data.name;
|
||||
}
|
||||
|
||||
get type(): string | undefined {
|
||||
return this._data.type;
|
||||
}
|
||||
|
||||
get charset(): string | null | undefined {
|
||||
return this._data.charset;
|
||||
}
|
||||
|
||||
get disposition(): string | null | undefined {
|
||||
return this._data.disposition;
|
||||
}
|
||||
|
||||
get cid(): string | null | undefined {
|
||||
return this._data.cid;
|
||||
}
|
||||
|
||||
get language(): string | null | undefined {
|
||||
return this._data.language;
|
||||
}
|
||||
|
||||
get location(): string | null | undefined {
|
||||
return this._data.location;
|
||||
}
|
||||
|
||||
get content(): string | undefined {
|
||||
return this._data.content;
|
||||
}
|
||||
|
||||
get subParts(): MessagePartInterface[] | undefined {
|
||||
return this._data.subParts;
|
||||
}
|
||||
|
||||
/** Helper methods */
|
||||
|
||||
hasContent(): boolean {
|
||||
return !!this._data.content;
|
||||
}
|
||||
|
||||
hasSubParts(): boolean {
|
||||
return !!this._data.subParts && this._data.subParts.length > 0;
|
||||
}
|
||||
|
||||
isMultipart(): boolean {
|
||||
return this._data.type?.startsWith('multipart/') ?? false;
|
||||
}
|
||||
|
||||
isText(): boolean {
|
||||
return this._data.type === 'text/plain';
|
||||
}
|
||||
|
||||
isHtml(): boolean {
|
||||
return this._data.type === 'text/html';
|
||||
}
|
||||
|
||||
isAttachment(): boolean {
|
||||
return this._data.disposition === 'attachment';
|
||||
}
|
||||
|
||||
isInline(): boolean {
|
||||
return this._data.disposition === 'inline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a part by partId (recursive search)
|
||||
*/
|
||||
findPartById(partId: string): MessagePartInterface | null {
|
||||
if (this._data.partId === partId) {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
if (this._data.subParts) {
|
||||
for (const subPart of this._data.subParts) {
|
||||
const part = new MessagePartObject(subPart);
|
||||
const found = part.findPartById(partId);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all parts of a specific type (recursive search)
|
||||
*/
|
||||
findPartsByType(type: string): MessagePartInterface[] {
|
||||
const parts: MessagePartInterface[] = [];
|
||||
|
||||
if (this._data.type === type) {
|
||||
parts.push(this._data);
|
||||
}
|
||||
|
||||
if (this._data.subParts) {
|
||||
for (const subPart of this._data.subParts) {
|
||||
const part = new MessagePartObject(subPart);
|
||||
parts.push(...part.findPartsByType(type));
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract text content from body structure
|
||||
*/
|
||||
extractTextContent(): string | null {
|
||||
if (this._data.type === 'text/plain' && this._data.content) {
|
||||
return this._data.content;
|
||||
}
|
||||
|
||||
if (this._data.subParts) {
|
||||
for (const subPart of this._data.subParts) {
|
||||
const part = new MessagePartObject(subPart);
|
||||
const content = part.extractTextContent();
|
||||
if (content) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract HTML content from body structure
|
||||
*/
|
||||
extractHtmlContent(): string | null {
|
||||
if (this._data.type === 'text/html' && this._data.content) {
|
||||
return this._data.content;
|
||||
}
|
||||
|
||||
if (this._data.subParts) {
|
||||
for (const subPart of this._data.subParts) {
|
||||
const part = new MessagePartObject(subPart);
|
||||
const content = part.extractHtmlContent();
|
||||
if (content) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Message class for working with message objects
|
||||
*/
|
||||
export class MessageObject {
|
||||
|
||||
_data: MessageInterface;
|
||||
_body: MessagePartObject | null = null;
|
||||
|
||||
constructor(data?: Partial<MessageInterface>) {
|
||||
this._data = {
|
||||
urid: data?.urid ?? undefined,
|
||||
size: data?.size ?? undefined,
|
||||
receivedDate: data?.receivedDate ?? undefined,
|
||||
date: data?.date ?? undefined,
|
||||
subject: data?.subject ?? undefined,
|
||||
snippet: data?.snippet ?? undefined,
|
||||
from: data?.from ?? undefined,
|
||||
to: data?.to ?? [],
|
||||
cc: data?.cc ?? [],
|
||||
bcc: data?.bcc ?? [],
|
||||
replyTo: data?.replyTo ?? [],
|
||||
flags: data?.flags ?? {},
|
||||
body: data?.body ?? undefined,
|
||||
attachments: data?.attachments ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
fromJson(data: MessageInterface): MessageObject {
|
||||
this._data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
toJson(): MessageInterface {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
clone(): MessageObject {
|
||||
return new MessageObject(JSON.parse(JSON.stringify(this._data)));
|
||||
}
|
||||
|
||||
/** Properties */
|
||||
|
||||
get urid(): string | undefined {
|
||||
return this._data.urid;
|
||||
}
|
||||
|
||||
get size(): number | undefined {
|
||||
return this._data.size;
|
||||
}
|
||||
|
||||
get receivedDate(): string | undefined {
|
||||
return this._data.receivedDate;
|
||||
}
|
||||
|
||||
get date(): string | undefined {
|
||||
return this._data.date;
|
||||
}
|
||||
|
||||
get subject(): string | undefined {
|
||||
return this._data.subject;
|
||||
}
|
||||
|
||||
get snippet(): string | undefined {
|
||||
return this._data.snippet;
|
||||
}
|
||||
|
||||
get from(): { address: string; label?: string } | undefined {
|
||||
return this._data.from;
|
||||
}
|
||||
|
||||
get to(): Array<{ address: string; label?: string }> | undefined {
|
||||
return this._data.to;
|
||||
}
|
||||
|
||||
get cc(): Array<{ address: string; label?: string }> | undefined {
|
||||
return this._data.cc;
|
||||
}
|
||||
|
||||
get bcc(): Array<{ address: string; label?: string }> | undefined {
|
||||
return this._data.bcc;
|
||||
}
|
||||
|
||||
get replyTo(): Array<{ address: string; label?: string }> | undefined {
|
||||
return this._data.replyTo;
|
||||
}
|
||||
|
||||
get flags(): { read?: boolean; flagged?: boolean; answered?: boolean; draft?: boolean } | undefined {
|
||||
return this._data.flags;
|
||||
}
|
||||
|
||||
get body(): MessagePartInterface | undefined {
|
||||
return this._data.body;
|
||||
}
|
||||
|
||||
get attachments(): MessageInterface['attachments'] {
|
||||
return this._data.attachments;
|
||||
}
|
||||
|
||||
/** Helper methods */
|
||||
|
||||
get isRead(): boolean {
|
||||
return this._data.flags?.read ?? false;
|
||||
}
|
||||
|
||||
get isFlagged(): boolean {
|
||||
return this._data.flags?.flagged ?? false;
|
||||
}
|
||||
|
||||
get isAnswered(): boolean {
|
||||
return this._data.flags?.answered ?? false;
|
||||
}
|
||||
|
||||
get isDraft(): boolean {
|
||||
return this._data.flags?.draft ?? false;
|
||||
}
|
||||
|
||||
get hasAttachments(): boolean {
|
||||
return (this._data.attachments?.length ?? 0) > 0;
|
||||
}
|
||||
|
||||
hasRecipients(): boolean {
|
||||
return (this._data.to?.length ?? 0) > 0
|
||||
|| (this._data.cc?.length ?? 0) > 0
|
||||
|| (this._data.bcc?.length ?? 0) > 0;
|
||||
}
|
||||
|
||||
/** Body content helpers */
|
||||
|
||||
getBody(): MessagePartObject | null {
|
||||
if (!this._body && this._data.body) {
|
||||
this._body = new MessagePartObject(this._data.body);
|
||||
}
|
||||
return this._body;
|
||||
}
|
||||
|
||||
hasContent(): boolean {
|
||||
return !!this.getTextContent() || !!this.getHtmlContent();
|
||||
}
|
||||
|
||||
hasTextContent(): boolean {
|
||||
return !!this.getTextContent();
|
||||
}
|
||||
|
||||
getTextContent(): string | null {
|
||||
const bodyPart = this.getBody();
|
||||
return bodyPart ? bodyPart.extractTextContent() : null;
|
||||
}
|
||||
|
||||
hasHtmlContent(): boolean {
|
||||
return !!this.getHtmlContent();
|
||||
}
|
||||
|
||||
getHtmlContent(): string | null {
|
||||
const bodyPart = this.getBody();
|
||||
return bodyPart ? bodyPart.extractHtmlContent() : null;
|
||||
}
|
||||
|
||||
findPartById(partId: string): MessagePartInterface | null {
|
||||
const bodyPart = this.getBody();
|
||||
return bodyPart ? bodyPart.findPartById(partId) : null;
|
||||
}
|
||||
|
||||
findPartsByType(type: string): MessagePartInterface[] {
|
||||
const bodyPart = this.getBody();
|
||||
return bodyPart ? bodyPart.findPartsByType(type) : [];
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user