From 0368bd1069366cb2c1f0e913db8b6016d8269c61 Mon Sep 17 00:00:00 2001 From: alma Date: Tue, 29 Apr 2025 11:24:39 +0200 Subject: [PATCH] courrier multi account restore compose --- app/api/courrier/route.ts | 19 +++++++++--- hooks/use-courrier.ts | 8 ++++- lib/services/prefetch-service.ts | 53 +++++++++++++++++++++----------- 3 files changed, 57 insertions(+), 23 deletions(-) diff --git a/app/api/courrier/route.ts b/app/api/courrier/route.ts index a34dc20a..6f20901c 100644 --- a/app/api/courrier/route.ts +++ b/app/api/courrier/route.ts @@ -82,20 +82,31 @@ export async function POST(request: Request) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } - const { emailId, folderName } = await request.json(); + const { emailId, folderName, accountId } = await request.json(); if (!emailId) { return NextResponse.json({ error: 'Missing emailId parameter' }, { status: 400 }); } + // Use account ID or default if not provided + const effectiveAccountId = accountId || 'default'; + + // Normalize folder name by removing account prefix if present + const normalizedFolder = folderName && folderName.includes(':') + ? folderName.split(':')[1] + : folderName; + + // Log the cache invalidation operation + console.log(`Invalidating cache for user ${session.user.id}, account ${effectiveAccountId}, folder ${normalizedFolder || 'all folders'}`); + // Invalidate Redis cache for the folder - if (folderName) { - await invalidateFolderCache(session.user.id, 'default', folderName); + if (normalizedFolder) { + await invalidateFolderCache(session.user.id, effectiveAccountId, normalizedFolder); } else { // If no folder specified, invalidate all folders (using a wildcard pattern) const folders = ['INBOX', 'Sent', 'Drafts', 'Trash', 'Junk']; for (const folder of folders) { - await invalidateFolderCache(session.user.id, 'default', folder); + await invalidateFolderCache(session.user.id, effectiveAccountId, folder); } } diff --git a/hooks/use-courrier.ts b/hooks/use-courrier.ts index 87485754..34df81e7 100644 --- a/hooks/use-courrier.ts +++ b/hooks/use-courrier.ts @@ -184,7 +184,13 @@ export const useCourrier = () => { setIsLoading(false); // Still refresh in background for fresh data - refreshEmailsInBackground(session.user.id, currentFolder, currentRequestPage, perPage).catch(err => { + refreshEmailsInBackground( + session.user.id, + currentFolder, + currentRequestPage, + perPage, + accountId // Make sure accountId is passed + ).catch(err => { console.error('Background refresh error:', err); }); return; diff --git a/lib/services/prefetch-service.ts b/lib/services/prefetch-service.ts index 3e886dbb..0c387b22 100644 --- a/lib/services/prefetch-service.ts +++ b/lib/services/prefetch-service.ts @@ -68,28 +68,35 @@ export async function getCachedEmailsWithTimeout( return null; } + // Extract account ID from folder name if present and none was explicitly provided + const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId; + + // Use the most specific account ID available + const effectiveAccountId = folderAccountId || accountId || 'default'; + // Normalize folder name by removing account prefix if present // This ensures consistent cache key format regardless of how folder name is passed const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder; // Log the normalization for debugging if (folder !== normalizedFolder) { - console.log(`Normalized folder name from ${folder} to ${normalizedFolder} for cache lookup`); + console.log(`Normalized folder name from ${folder} to ${normalizedFolder} for cache lookup with account ID ${effectiveAccountId}`); } return new Promise((resolve) => { const timeoutId = setTimeout(() => { - console.log(`Cache access timeout for ${userId}:${normalizedFolder}:${page}:${perPage}${accountId ? ` for account ${accountId}` : ''}`); + console.log(`Cache access timeout for ${userId}:${normalizedFolder}:${page}:${perPage} for account ${effectiveAccountId}`); resolve(null); }, timeoutMs); - getCachedEmailList(userId, accountId || 'default', normalizedFolder, page, perPage) + getCachedEmailList(userId, effectiveAccountId, normalizedFolder, page, perPage) .then(result => { clearTimeout(timeoutId); if (result) { - console.log(`Using cached data for ${userId}:${normalizedFolder}:${page}:${perPage}${accountId ? ` for account ${accountId}` : ''}`); + console.log(`Using cached data for ${userId}:${normalizedFolder}:${page}:${perPage} for account ${effectiveAccountId}`); resolve(result); } else { + console.log(`Redis cache miss for ${userId}:${effectiveAccountId}:${normalizedFolder}:${page}:${perPage}, fetching emails from IMAP`); resolve(null); } }) @@ -112,11 +119,16 @@ export async function refreshEmailsInBackground( perPage: number = 20, accountId?: string ): Promise { - // Normalize folder name by removing account prefix if present - const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder; + // Extract account ID from folder name if present and none was explicitly provided const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId; - const prefetchKey = `refresh:${normalizedFolder}:${page}:${folderAccountId || ''}`; + // Use the most specific account ID available + const effectiveAccountId = folderAccountId || accountId || 'default'; + + // Normalize folder name by removing account prefix if present + const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder; + + const prefetchKey = `refresh:${normalizedFolder}:${page}:${effectiveAccountId}`; // Skip if already in progress or in cooldown if (!shouldPrefetch(userId, prefetchKey)) { @@ -126,9 +138,9 @@ export async function refreshEmailsInBackground( // Use setTimeout to ensure this runs after current execution context setTimeout(async () => { try { - console.log(`Background refresh for ${userId}:${normalizedFolder}:${page}:${perPage}${folderAccountId ? ` for account ${folderAccountId}` : ''}`); - const freshData = await getEmails(userId, normalizedFolder, page, perPage, folderAccountId); - console.log(`Background refresh completed for ${userId}:${normalizedFolder}${folderAccountId ? ` for account ${folderAccountId}` : ''}`); + console.log(`Background refresh for ${userId}:${normalizedFolder}:${page}:${perPage} for account ${effectiveAccountId}`); + const freshData = await getEmails(userId, normalizedFolder, page, perPage, effectiveAccountId); + console.log(`Background refresh completed for ${userId}:${normalizedFolder} for account ${effectiveAccountId}`); } catch (error) { console.error('Background refresh error:', error); } finally { @@ -232,11 +244,16 @@ export async function prefetchFolderEmails( startPage: number = 1, accountId?: string ): Promise { - // Normalize folder name by removing account prefix if present - const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder; + // Extract account ID from folder name if present and none was explicitly provided const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId; - const prefetchKey = `folder:${normalizedFolder}:${startPage}:${folderAccountId || ''}`; + // Use the most specific account ID available + const effectiveAccountId = folderAccountId || accountId || 'default'; + + // Normalize folder name by removing account prefix if present + const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder; + + const prefetchKey = `folder:${normalizedFolder}:${startPage}:${effectiveAccountId}`; // Skip if already in progress or in cooldown if (!shouldPrefetch(userId, prefetchKey)) { @@ -244,7 +261,7 @@ export async function prefetchFolderEmails( } try { - console.log(`Prefetching ${pages} pages of emails for folder ${normalizedFolder} starting from page ${startPage}${folderAccountId ? ` for account ${folderAccountId}` : ''}`); + console.log(`Prefetching ${pages} pages of emails for folder ${normalizedFolder} starting from page ${startPage} for account ${effectiveAccountId}`); // Calculate the range of pages to prefetch const pagesToFetch = Array.from( @@ -257,19 +274,19 @@ export async function prefetchFolderEmails( // Fetch multiple pages in parallel await Promise.allSettled( pagesToFetch.map(page => - getEmails(userId, normalizedFolder, page, 20, folderAccountId) + getEmails(userId, normalizedFolder, page, 20, effectiveAccountId) .then(result => { - console.log(`Successfully prefetched and cached page ${page} of ${normalizedFolder} with ${result.emails.length} emails`); + console.log(`Successfully prefetched and cached page ${page} of ${normalizedFolder} with ${result.emails.length} emails for account ${effectiveAccountId}`); return result; }) .catch(err => { - console.error(`Error prefetching page ${page} of ${normalizedFolder}:`, err); + console.error(`Error prefetching page ${page} of ${normalizedFolder} for account ${effectiveAccountId}:`, err); return null; }) ) ); - console.log(`Completed prefetching ${pages} pages for ${normalizedFolder}`); + console.log(`Completed prefetching ${pages} pages for ${normalizedFolder} in account ${effectiveAccountId}`); } catch (error) { console.error(`Error during folder prefetch:`, error); } finally {