From aabf043b600c6bdf82d326e55bc8ab224b88e57f Mon Sep 17 00:00:00 2001 From: alma Date: Wed, 30 Apr 2025 14:52:08 +0200 Subject: [PATCH] courrier multi account restore compose --- app/api/courrier/unread-counts/route.ts | 66 +++++++++++++++++++------ 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/app/api/courrier/unread-counts/route.ts b/app/api/courrier/unread-counts/route.ts index af669f72..8a072527 100644 --- a/app/api/courrier/unread-counts/route.ts +++ b/app/api/courrier/unread-counts/route.ts @@ -2,11 +2,17 @@ import { NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/app/api/auth/[...nextauth]/route'; import { getImapConnection } from '@/lib/services/email-service'; +import { prisma } from '@/lib/prisma'; +import { getRedisClient } from '@/lib/redis'; + +// Cache TTL for unread counts (30 seconds) +const UNREAD_COUNTS_CACHE_TTL = 30; +// Key for unread counts cache +const UNREAD_COUNTS_CACHE_KEY = (userId: string) => `email:unread:${userId}`; /** * API route for fetching unread counts for email folders - * This solves the 500 error that occurred when the /unread-counts path was mistakenly being - * handled by the [id] route handler which expected a numeric ID + * Optimized with proper caching and connection reuse */ export async function GET(request: Request) { try { @@ -19,29 +25,53 @@ export async function GET(request: Request) { ); } - // Get all accounts from the user's session - const accountIds = await getUserAccountIds(session.user.id); - console.log(`[UNREAD_API] Got ${accountIds.length} accounts for user ${session.user.id}`); + const userId = session.user.id; + const redis = getRedisClient(); + + // First try to get from cache + const cachedCounts = await redis.get(UNREAD_COUNTS_CACHE_KEY(userId)); + if (cachedCounts) { + // Use cached results if available + console.log(`[UNREAD_API] Using cached unread counts for user ${userId}`); + return NextResponse.json(JSON.parse(cachedCounts)); + } + + console.log(`[UNREAD_API] Cache miss for user ${userId}, fetching unread counts`); + + // Get all accounts from the database directly + const accounts = await prisma.mailCredentials.findMany({ + where: { userId }, + select: { + id: true, + email: true + } + }); + + console.log(`[UNREAD_API] Found ${accounts.length} accounts for user ${userId}`); + + if (accounts.length === 0) { + return NextResponse.json({ default: {} }); + } // Mapping to hold the unread counts const unreadCounts: Record> = {}; // For each account, get the unread counts for standard folders - for (const accountId of accountIds) { + for (const account of accounts) { + const accountId = account.id; try { // Get IMAP connection for this account - const client = await getImapConnection(session.user.id, accountId); + console.log(`[UNREAD_API] Processing account ${accountId} (${account.email})`); + const client = await getImapConnection(userId, accountId); unreadCounts[accountId] = {}; // Standard folders to check - const standardFolders = ['INBOX', 'Sent', 'Drafts', 'Trash', 'Junk', 'Spam', 'Archive', 'Sent Items']; + const standardFolders = ['INBOX', 'Sent', 'Drafts', 'Trash', 'Junk', 'Spam', 'Archive', 'Sent Items', 'Archives', 'Notes', 'Éléments supprimés']; // Get mailboxes for this account to check if folders exist const mailboxes = await client.list(); const availableFolders = mailboxes.map(mb => mb.path); - console.log(`[UNREAD_API] Account ${accountId} has folders: ${availableFolders.join(', ')}`); - // Check each standard folder if it exists for (const folder of standardFolders) { // Skip if folder doesn't exist in this account @@ -51,7 +81,7 @@ export async function GET(request: Request) { } try { - // Open the mailbox + // Check folder status without opening it (more efficient) const status = await client.status(folder, { unseen: true }); if (status && typeof status.unseen === 'number') { @@ -69,15 +99,21 @@ export async function GET(request: Request) { } } - // Close connection when done - await client.logout(); - + // Don't close the connection - let the connection pool handle it + // This avoids opening and closing connections repeatedly } catch (accountError) { console.error(`[UNREAD_API] Error processing account ${accountId}:`, accountError); - // Continue to next account even if this one fails } } + // Save to cache for 30 seconds to avoid hammering the IMAP server + await redis.set( + UNREAD_COUNTS_CACHE_KEY(userId), + JSON.stringify(unreadCounts), + 'EX', + UNREAD_COUNTS_CACHE_TTL + ); + return NextResponse.json(unreadCounts); } catch (error: any) { console.error("[UNREAD_API] Error fetching unread counts:", error);