courrier multi account restore compose
This commit is contained in:
parent
b78590727b
commit
542a535ce1
@ -1,15 +1,11 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/lib/auth';
|
||||
import { getUserEmailCredentials, getMailboxes } from '@/lib/services/email-service';
|
||||
import { prefetchUserEmailData } from '@/lib/services/prefetch-service';
|
||||
import { getCachedEmailCredentials, getRedisStatus, warmupRedisCache, getCachedImapSession, cacheImapSession } from '@/lib/redis';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { ImapFlow } from 'imapflow';
|
||||
import { getMailboxes } from '@/lib/services/email-service';
|
||||
import { getRedisClient } from '@/lib/redis';
|
||||
import { getImapConnection } from '@/lib/services/email-service';
|
||||
import { MailCredentials } from '@prisma/client';
|
||||
import { redis } from '@/lib/redis';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
|
||||
// Keep track of last prefetch time for each user
|
||||
const lastPrefetchMap = new Map<string, number>();
|
||||
@ -18,63 +14,9 @@ const PREFETCH_COOLDOWN_MS = 30000; // 30 seconds cooldown between prefetches
|
||||
// Cache TTL for folders in Redis (5 minutes)
|
||||
const FOLDERS_CACHE_TTL = 3600; // 1 hour
|
||||
|
||||
// Cache to store account folders to avoid repeated calls to the IMAP server
|
||||
// const accountFoldersCache = new Map<string, string[]>();
|
||||
|
||||
// Redis key for folders cache
|
||||
const FOLDERS_CACHE_KEY = (userId: string, accountId: string) => `email:folders:${userId}:${accountId}`;
|
||||
|
||||
/**
|
||||
* Get folders for a specific account
|
||||
*/
|
||||
async function getAccountFolders(accountId: string, account: any): Promise<string[]> {
|
||||
// Check cache first
|
||||
const cacheKey = `folders:${accountId}`;
|
||||
const cachedData = accountFoldersCache.get(cacheKey);
|
||||
const now = Date.now();
|
||||
|
||||
if (cachedData && (now - cachedData.timestamp < FOLDERS_CACHE_TTL)) {
|
||||
return cachedData.folders;
|
||||
}
|
||||
|
||||
try {
|
||||
// Connect to IMAP server for this account
|
||||
const client = new ImapFlow({
|
||||
host: account.host,
|
||||
port: account.port,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: account.email,
|
||||
pass: account.password,
|
||||
},
|
||||
logger: false,
|
||||
tls: {
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
});
|
||||
|
||||
await client.connect();
|
||||
|
||||
// Get folders for this account
|
||||
const folders = await getMailboxes(client);
|
||||
|
||||
// Close connection
|
||||
await client.logout();
|
||||
|
||||
// Cache the result
|
||||
accountFoldersCache.set(cacheKey, {
|
||||
folders,
|
||||
timestamp: now
|
||||
});
|
||||
|
||||
return folders;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching folders for account ${account.email}:`, error);
|
||||
// Return fallback folders on error
|
||||
return ['INBOX', 'Sent', 'Drafts', 'Trash'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is called when the app initializes to check if the user has email credentials
|
||||
* and to start prefetching email data in the background if they do
|
||||
@ -103,14 +45,14 @@ export async function GET() {
|
||||
}
|
||||
|
||||
// Get all accounts for the user
|
||||
const accounts: MailCredentials[] = user.mailCredentials || [];
|
||||
const accounts = (user.mailCredentials || []) as MailCredentials[];
|
||||
if (accounts.length === 0) {
|
||||
return NextResponse.json({ error: 'No email accounts found' }, { status: 404 });
|
||||
}
|
||||
|
||||
// Fetch folders for each account
|
||||
const accountsWithFolders = await Promise.all(
|
||||
accounts.map(async (account) => {
|
||||
accounts.map(async (account: MailCredentials) => {
|
||||
const cacheKey = FOLDERS_CACHE_KEY(user.id, account.id);
|
||||
// Try to get folders from Redis cache first
|
||||
const cachedFolders = await redis.get(cacheKey);
|
||||
@ -122,7 +64,7 @@ export async function GET() {
|
||||
}
|
||||
|
||||
// If not in cache, fetch from IMAP
|
||||
const client = await getImapConnection(account);
|
||||
const client = await getImapConnection(user.id, account.id);
|
||||
if (!client) {
|
||||
return {
|
||||
...account,
|
||||
|
||||
@ -66,7 +66,7 @@ export async function getImapConnection(
|
||||
// If not in cache, get from database and cache them
|
||||
if (!credentials) {
|
||||
console.log(`Credentials not found in cache for ${userId}${accountId ? ` account ${accountId}` : ''}, attempting database lookup`);
|
||||
credentials = await getUserEmailCredentials(userId);
|
||||
credentials = await getUserEmailCredentials(userId, accountId);
|
||||
if (!credentials) {
|
||||
throw new Error('No email credentials found');
|
||||
}
|
||||
@ -154,24 +154,37 @@ export async function getImapConnection(
|
||||
/**
|
||||
* Get user's email credentials from database
|
||||
*/
|
||||
export async function getUserEmailCredentials(userId: string): Promise<EmailCredentials | null> {
|
||||
export async function getUserEmailCredentials(userId: string, accountId?: string): Promise<EmailCredentials | null> {
|
||||
const credentials = await prisma.mailCredentials.findFirst({
|
||||
where: { userId }
|
||||
where: accountId ? { userId, id: accountId } : { userId }
|
||||
});
|
||||
|
||||
if (!credentials) return null;
|
||||
|
||||
const mailCredentials = credentials as unknown as {
|
||||
email: string;
|
||||
password: string;
|
||||
host: string;
|
||||
port: number;
|
||||
secure: boolean;
|
||||
smtp_host: string | null;
|
||||
smtp_port: number | null;
|
||||
smtp_secure: boolean | null;
|
||||
display_name: string | null;
|
||||
color: string | null;
|
||||
};
|
||||
|
||||
return {
|
||||
email: credentials.email,
|
||||
password: credentials.password,
|
||||
host: credentials.host,
|
||||
port: credentials.port,
|
||||
secure: credentials.secure,
|
||||
smtp_host: credentials.smtp_host,
|
||||
smtp_port: credentials.smtp_port,
|
||||
smtp_secure: credentials.smtp_secure,
|
||||
display_name: credentials.display_name,
|
||||
color: credentials.color
|
||||
email: mailCredentials.email,
|
||||
password: mailCredentials.password,
|
||||
host: mailCredentials.host,
|
||||
port: mailCredentials.port,
|
||||
secure: mailCredentials.secure,
|
||||
smtp_host: mailCredentials.smtp_host || undefined,
|
||||
smtp_port: mailCredentials.smtp_port || undefined,
|
||||
smtp_secure: mailCredentials.smtp_secure || false,
|
||||
display_name: mailCredentials.display_name || undefined,
|
||||
color: mailCredentials.color || undefined
|
||||
};
|
||||
}
|
||||
|
||||
@ -235,7 +248,7 @@ export async function getEmails(
|
||||
// Try to get from cache first
|
||||
if (!searchQuery) {
|
||||
const cacheKey = accountId ? `${userId}:${accountId}:${folder}` : `${userId}:${folder}`;
|
||||
const cachedResult = await getCachedEmailList(userId, folder, page, perPage);
|
||||
const cachedResult = await getCachedEmailList(userId, accountId || 'default', folder, page, perPage);
|
||||
if (cachedResult) {
|
||||
console.log(`Using cached email list for ${cacheKey}:${page}:${perPage}`);
|
||||
return cachedResult;
|
||||
@ -331,7 +344,7 @@ export async function getEmails(
|
||||
|
||||
// Cache even empty results
|
||||
if (!searchQuery) {
|
||||
await cacheEmailList(userId, folder, page, perPage, result);
|
||||
await cacheEmailList(userId, accountId || 'default', folder, page, perPage, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -476,7 +489,7 @@ export async function getEmails(
|
||||
// Always cache the result if it's not a search query, even for pagination
|
||||
if (!searchQuery) {
|
||||
console.log(`Caching email list for ${userId}:${folder}:${page}:${perPage}`);
|
||||
await cacheEmailList(userId, folder, page, perPage, result);
|
||||
await cacheEmailList(userId, accountId || 'default', folder, page, perPage, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -501,7 +514,7 @@ export async function getEmailContent(
|
||||
folder: string = 'INBOX'
|
||||
): Promise<EmailMessage> {
|
||||
// Try to get from cache first
|
||||
const cachedEmail = await getCachedEmailContent(userId, emailId);
|
||||
const cachedEmail = await getCachedEmailContent(userId, folder, emailId);
|
||||
if (cachedEmail) {
|
||||
console.log(`Using cached email content for ${userId}:${emailId}`);
|
||||
return cachedEmail;
|
||||
@ -582,7 +595,7 @@ export async function getEmailContent(
|
||||
};
|
||||
|
||||
// Cache the email content
|
||||
await cacheEmailContent(userId, emailId, email);
|
||||
await cacheEmailContent(userId, folder, emailId, email);
|
||||
|
||||
return email;
|
||||
} finally {
|
||||
@ -615,10 +628,10 @@ export async function markEmailReadStatus(
|
||||
}
|
||||
|
||||
// Invalidate content cache since the flags changed
|
||||
await invalidateEmailContentCache(userId, emailId);
|
||||
await invalidateEmailContentCache(userId, folder, emailId);
|
||||
|
||||
// Also invalidate folder cache because unread counts may have changed
|
||||
await invalidateFolderCache(userId, folder);
|
||||
await invalidateFolderCache(userId, folder, folder);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user