Agenda Sync refactor Mig Graph
This commit is contained in:
parent
dbbc2ff59a
commit
13a2996446
@ -982,7 +982,9 @@ export async function getEmails(
|
|||||||
totalPages: Math.ceil(totalEmails / perPage),
|
totalPages: Math.ceil(totalEmails / perPage),
|
||||||
folder,
|
folder,
|
||||||
mailboxes,
|
mailboxes,
|
||||||
newestEmailId: emails.length > 0 ? parseInt(emails[0].id) || 0 : 0,
|
// For Graph API, IDs are strings, so we can't use parseInt
|
||||||
|
// Use a hash or just use the first email's ID as string, then convert to number if needed
|
||||||
|
newestEmailId: emails.length > 0 ? (emails[0].id.match(/^\d+$/) ? parseInt(emails[0].id) : 0) : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cache the result
|
// Cache the result
|
||||||
@ -1219,6 +1221,7 @@ function mapAddresses(addresses: any[] | undefined): Array<{ name: string; addre
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a single email with full content
|
* Get a single email with full content
|
||||||
|
* Supports both IMAP (numeric UIDs) and Microsoft Graph API (string IDs)
|
||||||
*/
|
*/
|
||||||
export async function getEmailContent(
|
export async function getEmailContent(
|
||||||
userId: string,
|
userId: string,
|
||||||
@ -1231,17 +1234,6 @@ export async function getEmailContent(
|
|||||||
throw new Error('Missing required parameters');
|
throw new Error('Missing required parameters');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate UID format
|
|
||||||
if (!/^\d+$/.test(emailId)) {
|
|
||||||
throw new Error('Invalid email ID format: must be a numeric UID');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to number for IMAP
|
|
||||||
const numericId = parseInt(emailId, 10);
|
|
||||||
if (isNaN(numericId)) {
|
|
||||||
throw new Error('Email ID must be a number');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract account ID from folder name if present and none was explicitly provided
|
// Extract account ID from folder name if present and none was explicitly provided
|
||||||
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId;
|
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId;
|
||||||
|
|
||||||
@ -1258,6 +1250,99 @@ export async function getEmailContent(
|
|||||||
accountId: effectiveAccountId,
|
accountId: effectiveAccountId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Check if this is a Microsoft account that should use Graph API
|
||||||
|
// Graph API uses string IDs (not numeric UIDs), so if emailId is not numeric, it's likely Graph
|
||||||
|
const isGraphId = !/^\d+$/.test(emailId);
|
||||||
|
const graphCheck = await shouldUseGraphAPI(userId, effectiveAccountId);
|
||||||
|
|
||||||
|
if (isGraphId && graphCheck.useGraph && graphCheck.mailCredentialId) {
|
||||||
|
// Use Microsoft Graph API for Microsoft accounts with Graph IDs
|
||||||
|
logger.debug('[EMAIL] Fetching email content via Microsoft Graph API', {
|
||||||
|
userId,
|
||||||
|
emailId,
|
||||||
|
mailCredentialId: graphCheck.mailCredentialId,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use normalized folder name and effective account ID for cache key
|
||||||
|
const cachedEmail = await getCachedEmailContent(userId, effectiveAccountId, emailId);
|
||||||
|
if (cachedEmail) {
|
||||||
|
logger.debug('[EMAIL] Using cached email content (Graph)', {
|
||||||
|
userId,
|
||||||
|
accountId: effectiveAccountId,
|
||||||
|
emailId,
|
||||||
|
});
|
||||||
|
return cachedEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch from Graph API
|
||||||
|
const { fetchGraphEmail } = await import('./microsoft-graph-mail');
|
||||||
|
const graphMessage = await fetchGraphEmail(graphCheck.mailCredentialId, emailId);
|
||||||
|
|
||||||
|
// Convert Graph message to EmailMessage format
|
||||||
|
const email: EmailMessage = {
|
||||||
|
id: graphMessage.id,
|
||||||
|
from: graphMessage.from ? [{
|
||||||
|
name: graphMessage.from.emailAddress.name || '',
|
||||||
|
address: graphMessage.from.emailAddress.address,
|
||||||
|
}] : [],
|
||||||
|
to: graphMessage.toRecipients?.map(recipient => ({
|
||||||
|
name: recipient.emailAddress.name || '',
|
||||||
|
address: recipient.emailAddress.address,
|
||||||
|
})) || [],
|
||||||
|
cc: graphMessage.ccRecipients?.map(recipient => ({
|
||||||
|
name: recipient.emailAddress.name || '',
|
||||||
|
address: recipient.emailAddress.address,
|
||||||
|
})),
|
||||||
|
subject: graphMessage.subject || '',
|
||||||
|
date: new Date(graphMessage.receivedDateTime),
|
||||||
|
flags: {
|
||||||
|
seen: graphMessage.isRead,
|
||||||
|
flagged: graphMessage.flag?.flagStatus === 'flagged' || graphMessage.flag?.flagStatus === 'complete',
|
||||||
|
answered: false,
|
||||||
|
draft: false,
|
||||||
|
deleted: false,
|
||||||
|
},
|
||||||
|
size: 0,
|
||||||
|
hasAttachments: graphMessage.hasAttachments || false,
|
||||||
|
folder: normalizedFolder,
|
||||||
|
contentFetched: true,
|
||||||
|
accountId: effectiveAccountId,
|
||||||
|
content: {
|
||||||
|
text: graphMessage.body?.contentType === 'text' ? (graphMessage.body.content || '') : '',
|
||||||
|
html: graphMessage.body?.contentType === 'html' ? (graphMessage.body.content || '') : (graphMessage.bodyPreview || ''),
|
||||||
|
isHtml: graphMessage.body?.contentType === 'html',
|
||||||
|
direction: 'ltr',
|
||||||
|
},
|
||||||
|
preview: graphMessage.bodyPreview,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cache the email content
|
||||||
|
await cacheEmailContent(userId, effectiveAccountId, emailId, email);
|
||||||
|
|
||||||
|
return email;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('[EMAIL] Error fetching email content from Graph API', {
|
||||||
|
userId,
|
||||||
|
emailId,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use IMAP for non-Microsoft accounts or numeric UIDs
|
||||||
|
// Validate UID format for IMAP
|
||||||
|
if (!/^\d+$/.test(emailId)) {
|
||||||
|
throw new Error('Invalid email ID format: must be a numeric UID for IMAP accounts');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to number for IMAP
|
||||||
|
const numericId = parseInt(emailId, 10);
|
||||||
|
if (isNaN(numericId)) {
|
||||||
|
throw new Error('Email ID must be a number for IMAP accounts');
|
||||||
|
}
|
||||||
|
|
||||||
// Use normalized folder name and effective account ID for cache key
|
// Use normalized folder name and effective account ID for cache key
|
||||||
const cachedEmail = await getCachedEmailContent(userId, effectiveAccountId, emailId);
|
const cachedEmail = await getCachedEmailContent(userId, effectiveAccountId, emailId);
|
||||||
if (cachedEmail) {
|
if (cachedEmail) {
|
||||||
@ -1441,6 +1526,7 @@ export async function getEmailContent(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark an email as read or unread
|
* Mark an email as read or unread
|
||||||
|
* Supports both IMAP (numeric UIDs) and Microsoft Graph API (string IDs)
|
||||||
*/
|
*/
|
||||||
export async function markEmailReadStatus(
|
export async function markEmailReadStatus(
|
||||||
userId: string,
|
userId: string,
|
||||||
@ -1466,6 +1552,41 @@ export async function markEmailReadStatus(
|
|||||||
accountId: effectiveAccountId,
|
accountId: effectiveAccountId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Check if this is a Microsoft account that should use Graph API
|
||||||
|
// Graph API uses string IDs (not numeric UIDs), so if emailId is not numeric, it's likely Graph
|
||||||
|
const isGraphId = !/^\d+$/.test(emailId);
|
||||||
|
const graphCheck = await shouldUseGraphAPI(userId, effectiveAccountId);
|
||||||
|
|
||||||
|
if (isGraphId && graphCheck.useGraph && graphCheck.mailCredentialId) {
|
||||||
|
// Use Microsoft Graph API for Microsoft accounts with Graph IDs
|
||||||
|
logger.debug('[EMAIL] Marking email as read/unread via Microsoft Graph API', {
|
||||||
|
userId,
|
||||||
|
emailId,
|
||||||
|
isRead,
|
||||||
|
mailCredentialId: graphCheck.mailCredentialId,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { markGraphEmailAsRead } = await import('./microsoft-graph-mail');
|
||||||
|
await markGraphEmailAsRead(graphCheck.mailCredentialId, emailId, isRead);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('[EMAIL] Error marking email as read/unread via Graph API', {
|
||||||
|
userId,
|
||||||
|
emailId,
|
||||||
|
isRead,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use IMAP for non-Microsoft accounts or numeric UIDs
|
||||||
|
// Validate UID format for IMAP
|
||||||
|
if (!/^\d+$/.test(emailId)) {
|
||||||
|
throw new Error('Invalid email ID format: must be a numeric UID for IMAP accounts');
|
||||||
|
}
|
||||||
|
|
||||||
const client = await getImapConnection(userId, effectiveAccountId);
|
const client = await getImapConnection(userId, effectiveAccountId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user