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),
|
||||
folder,
|
||||
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
|
||||
@ -1219,6 +1221,7 @@ function mapAddresses(addresses: any[] | undefined): Array<{ name: string; addre
|
||||
|
||||
/**
|
||||
* Get a single email with full content
|
||||
* Supports both IMAP (numeric UIDs) and Microsoft Graph API (string IDs)
|
||||
*/
|
||||
export async function getEmailContent(
|
||||
userId: string,
|
||||
@ -1231,17 +1234,6 @@ export async function getEmailContent(
|
||||
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
|
||||
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId;
|
||||
|
||||
@ -1258,6 +1250,99 @@ export async function getEmailContent(
|
||||
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
|
||||
const cachedEmail = await getCachedEmailContent(userId, effectiveAccountId, emailId);
|
||||
if (cachedEmail) {
|
||||
@ -1441,6 +1526,7 @@ export async function getEmailContent(
|
||||
|
||||
/**
|
||||
* Mark an email as read or unread
|
||||
* Supports both IMAP (numeric UIDs) and Microsoft Graph API (string IDs)
|
||||
*/
|
||||
export async function markEmailReadStatus(
|
||||
userId: string,
|
||||
@ -1466,6 +1552,41 @@ export async function markEmailReadStatus(
|
||||
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);
|
||||
|
||||
try {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user