courrier multi account
This commit is contained in:
parent
9797e08533
commit
3d69698964
167
app/api/courrier/debug-account/route.ts
Normal file
167
app/api/courrier/debug-account/route.ts
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { getServerSession } from 'next-auth';
|
||||||
|
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
|
||||||
|
import { getCachedEmailCredentials, getCachedImapSession } from '@/lib/redis';
|
||||||
|
import { prisma } from '@/lib/prisma';
|
||||||
|
import { getMailboxes } from '@/lib/services/email-service';
|
||||||
|
import { ImapFlow } from 'imapflow';
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
// Verify auth
|
||||||
|
const session = await getServerSession(authOptions);
|
||||||
|
if (!session?.user?.id) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Unauthorized' },
|
||||||
|
{ status: 401 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userId = session.user.id;
|
||||||
|
const debugData: any = {
|
||||||
|
userId,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
redis: {
|
||||||
|
emailCredentials: null,
|
||||||
|
session: null
|
||||||
|
},
|
||||||
|
database: {
|
||||||
|
accounts: []
|
||||||
|
},
|
||||||
|
imap: {
|
||||||
|
connectionAttempt: false,
|
||||||
|
connected: false,
|
||||||
|
folders: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check Redis cache for credentials
|
||||||
|
try {
|
||||||
|
const credentials = await getCachedEmailCredentials(userId);
|
||||||
|
if (credentials) {
|
||||||
|
debugData.redis.emailCredentials = {
|
||||||
|
found: true,
|
||||||
|
email: credentials.email,
|
||||||
|
host: credentials.host,
|
||||||
|
port: credentials.port,
|
||||||
|
hasPassword: !!credentials.password,
|
||||||
|
hasSmtp: !!credentials.smtp_host
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
debugData.redis.emailCredentials = { found: false };
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugData.redis.emailCredentials = {
|
||||||
|
error: e instanceof Error ? e.message : 'Unknown error'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Redis for session data (which contains folders)
|
||||||
|
try {
|
||||||
|
const sessionData = await getCachedImapSession(userId);
|
||||||
|
if (sessionData) {
|
||||||
|
debugData.redis.session = {
|
||||||
|
found: true,
|
||||||
|
lastActive: new Date(sessionData.lastActive).toISOString(),
|
||||||
|
hasFolders: !!sessionData.mailboxes,
|
||||||
|
folderCount: sessionData.mailboxes?.length || 0,
|
||||||
|
folders: sessionData.mailboxes || []
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
debugData.redis.session = { found: false };
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugData.redis.session = {
|
||||||
|
error: e instanceof Error ? e.message : 'Unknown error'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check database for accounts
|
||||||
|
try {
|
||||||
|
const accounts = await prisma.mailCredentials.findMany({
|
||||||
|
where: { userId },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
host: true,
|
||||||
|
port: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also try to get additional fields from raw query
|
||||||
|
const accountsWithMetadata = await Promise.all(accounts.map(async (account) => {
|
||||||
|
try {
|
||||||
|
const rawAccount = await prisma.$queryRaw`
|
||||||
|
SELECT display_name, color, smtp_host, smtp_port, smtp_secure, secure
|
||||||
|
FROM "MailCredentials"
|
||||||
|
WHERE id = ${account.id}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const metadata = Array.isArray(rawAccount) && rawAccount.length > 0
|
||||||
|
? rawAccount[0]
|
||||||
|
: {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...account,
|
||||||
|
display_name: metadata.display_name,
|
||||||
|
color: metadata.color,
|
||||||
|
smtp_host: metadata.smtp_host,
|
||||||
|
smtp_port: metadata.smtp_port,
|
||||||
|
smtp_secure: metadata.smtp_secure,
|
||||||
|
secure: metadata.secure
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
...account,
|
||||||
|
_queryError: e instanceof Error ? e.message : 'Unknown error'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
debugData.database.accounts = accountsWithMetadata;
|
||||||
|
debugData.database.accountCount = accounts.length;
|
||||||
|
} catch (e) {
|
||||||
|
debugData.database.error = e instanceof Error ? e.message : 'Unknown error';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get IMAP folders for the main account
|
||||||
|
if (debugData.redis.emailCredentials?.found || debugData.database.accountCount > 0) {
|
||||||
|
try {
|
||||||
|
debugData.imap.connectionAttempt = true;
|
||||||
|
|
||||||
|
// Use cached credentials
|
||||||
|
const credentials = await getCachedEmailCredentials(userId);
|
||||||
|
|
||||||
|
if (credentials && credentials.email && credentials.password) {
|
||||||
|
const client = new ImapFlow({
|
||||||
|
host: credentials.host,
|
||||||
|
port: credentials.port,
|
||||||
|
secure: true,
|
||||||
|
auth: {
|
||||||
|
user: credentials.email,
|
||||||
|
pass: credentials.password,
|
||||||
|
},
|
||||||
|
logger: false,
|
||||||
|
tls: {
|
||||||
|
rejectUnauthorized: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.connect();
|
||||||
|
debugData.imap.connected = true;
|
||||||
|
|
||||||
|
// Get folders
|
||||||
|
const folders = await getMailboxes(client);
|
||||||
|
debugData.imap.folders = folders;
|
||||||
|
|
||||||
|
// Close connection
|
||||||
|
await client.logout();
|
||||||
|
} else {
|
||||||
|
debugData.imap.error = "No valid credentials found";
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugData.imap.error = e instanceof Error ? e.message : 'Unknown error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json(debugData);
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import { authOptions } from '@/app/api/auth/[...nextauth]/route';
|
|||||||
import { getUserEmailCredentials } from '@/lib/services/email-service';
|
import { getUserEmailCredentials } from '@/lib/services/email-service';
|
||||||
import { prefetchUserEmailData } from '@/lib/services/prefetch-service';
|
import { prefetchUserEmailData } from '@/lib/services/prefetch-service';
|
||||||
import { getCachedEmailCredentials, getRedisStatus, warmupRedisCache, getCachedImapSession, cacheImapSession } from '@/lib/redis';
|
import { getCachedEmailCredentials, getRedisStatus, warmupRedisCache, getCachedImapSession, cacheImapSession } from '@/lib/redis';
|
||||||
|
import { prisma } from '@/lib/prisma';
|
||||||
|
|
||||||
// Keep track of last prefetch time for each user
|
// Keep track of last prefetch time for each user
|
||||||
const lastPrefetchMap = new Map<string, number>();
|
const lastPrefetchMap = new Map<string, number>();
|
||||||
@ -42,66 +43,131 @@ export async function GET() {
|
|||||||
|
|
||||||
// Check if we have a cached session
|
// Check if we have a cached session
|
||||||
const cachedSession = await getCachedImapSession(userId);
|
const cachedSession = await getCachedImapSession(userId);
|
||||||
|
console.log(`[DEBUG] Cached session for user ${userId}:`,
|
||||||
|
cachedSession ? {
|
||||||
|
hasMailboxes: Array.isArray(cachedSession.mailboxes),
|
||||||
|
mailboxCount: cachedSession.mailboxes?.length || 0
|
||||||
|
} : 'null');
|
||||||
|
|
||||||
// First, check Redis cache for credentials
|
// First, check Redis cache for credentials - this is for backward compatibility
|
||||||
let credentials = await getCachedEmailCredentials(userId);
|
let credentials = await getCachedEmailCredentials(userId);
|
||||||
|
console.log(`[DEBUG] Cached credentials for user ${userId}:`,
|
||||||
|
credentials ? { email: credentials.email, hasPassword: !!credentials.password } : 'null');
|
||||||
let credentialsSource = 'cache';
|
let credentialsSource = 'cache';
|
||||||
|
|
||||||
// If not in cache, check database
|
// Now fetch all email accounts for this user
|
||||||
if (!credentials) {
|
// Query the database directly using Prisma
|
||||||
credentials = await getUserEmailCredentials(userId);
|
try {
|
||||||
credentialsSource = 'database';
|
const allAccounts = await prisma.mailCredentials.findMany({
|
||||||
}
|
where: { userId },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
host: true,
|
||||||
|
port: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(`[DEBUG] Found ${allAccounts.length} accounts in database for user ${userId}:`);
|
||||||
|
allAccounts.forEach((account, idx) => {
|
||||||
|
console.log(`[DEBUG] Account ${idx + 1}: ID=${account.id}, Email=${account.email}`);
|
||||||
|
});
|
||||||
|
|
||||||
// If no credentials found
|
// Get additional fields that might be in the database but not in the type
|
||||||
if (!credentials) {
|
const accountsWithMetadata = await Promise.all(allAccounts.map(async (account) => {
|
||||||
|
// Get the raw account data to access fields not in the type
|
||||||
|
const rawAccount = await prisma.$queryRaw`
|
||||||
|
SELECT display_name, color
|
||||||
|
FROM "MailCredentials"
|
||||||
|
WHERE id = ${account.id}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Cast the raw result to an array and get the first item
|
||||||
|
const metadata = Array.isArray(rawAccount) ? rawAccount[0] : rawAccount;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...account,
|
||||||
|
display_name: metadata?.display_name || account.email,
|
||||||
|
color: metadata?.color || "#0082c9"
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log(`Found ${allAccounts.length} email accounts for user ${userId}`);
|
||||||
|
|
||||||
|
// If not in cache and no accounts found, check database for single account (backward compatibility)
|
||||||
|
if (!credentials && allAccounts.length === 0) {
|
||||||
|
credentials = await getUserEmailCredentials(userId);
|
||||||
|
credentialsSource = 'database';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no credentials found
|
||||||
|
if (!credentials && allAccounts.length === 0) {
|
||||||
|
return NextResponse.json({
|
||||||
|
authenticated: true,
|
||||||
|
hasEmailCredentials: false,
|
||||||
|
redisStatus,
|
||||||
|
message: "No email credentials found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let prefetchStarted = false;
|
||||||
|
|
||||||
|
// Only prefetch if the cooldown period has elapsed
|
||||||
|
if (shouldPrefetch) {
|
||||||
|
// Update the last prefetch time
|
||||||
|
lastPrefetchMap.set(userId, now);
|
||||||
|
|
||||||
|
// Start prefetching email data in the background
|
||||||
|
// We don't await this to avoid blocking the response
|
||||||
|
prefetchUserEmailData(userId).catch(err => {
|
||||||
|
console.error('Background prefetch error:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
prefetchStarted = true;
|
||||||
|
} else {
|
||||||
|
console.log(`Skipping prefetch for ${userId}, last prefetch was ${Math.round((now - lastPrefetchTime)/1000)}s ago`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store last visit time in session data
|
||||||
|
if (cachedSession) {
|
||||||
|
await cacheImapSession(userId, {
|
||||||
|
...cachedSession,
|
||||||
|
lastActive: cachedSession.lastActive || Date.now(), // Ensure lastActive is set
|
||||||
|
lastVisit: now
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await cacheImapSession(userId, {
|
||||||
|
lastActive: Date.now(),
|
||||||
|
lastVisit: now
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return all accounts information
|
||||||
|
return NextResponse.json({
|
||||||
|
authenticated: true,
|
||||||
|
hasEmailCredentials: true,
|
||||||
|
email: credentials?.email || (allAccounts.length > 0 ? allAccounts[0].email : ''),
|
||||||
|
redisStatus,
|
||||||
|
prefetchStarted,
|
||||||
|
credentialsSource,
|
||||||
|
lastVisit: cachedSession?.lastVisit,
|
||||||
|
mailboxes: cachedSession?.mailboxes || [],
|
||||||
|
allAccounts: accountsWithMetadata.map(account => ({
|
||||||
|
id: account.id,
|
||||||
|
email: account.email,
|
||||||
|
display_name: account.display_name || account.email,
|
||||||
|
color: account.color || "#0082c9"
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
} catch (dbError) {
|
||||||
|
console.error(`[ERROR] Database query failed:`, dbError);
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
authenticated: true,
|
authenticated: true,
|
||||||
hasEmailCredentials: false,
|
hasEmailCredentials: false,
|
||||||
redisStatus,
|
error: "Database query failed",
|
||||||
message: "No email credentials found"
|
details: dbError instanceof Error ? dbError.message : "Unknown database error",
|
||||||
});
|
redisStatus
|
||||||
|
}, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefetchStarted = false;
|
|
||||||
|
|
||||||
// Only prefetch if the cooldown period has elapsed
|
|
||||||
if (shouldPrefetch) {
|
|
||||||
// Update the last prefetch time
|
|
||||||
lastPrefetchMap.set(userId, now);
|
|
||||||
|
|
||||||
// Start prefetching email data in the background
|
|
||||||
// We don't await this to avoid blocking the response
|
|
||||||
prefetchUserEmailData(userId).catch(err => {
|
|
||||||
console.error('Background prefetch error:', err);
|
|
||||||
});
|
|
||||||
|
|
||||||
prefetchStarted = true;
|
|
||||||
} else {
|
|
||||||
console.log(`Skipping prefetch for ${userId}, last prefetch was ${Math.round((now - lastPrefetchTime)/1000)}s ago`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store last visit time in session data
|
|
||||||
if (cachedSession) {
|
|
||||||
await cacheImapSession(userId, {
|
|
||||||
...cachedSession,
|
|
||||||
lastVisit: now
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await cacheImapSession(userId, { lastVisit: now });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return session info without sensitive data
|
|
||||||
return NextResponse.json({
|
|
||||||
authenticated: true,
|
|
||||||
hasEmailCredentials: true,
|
|
||||||
email: credentials.email,
|
|
||||||
redisStatus,
|
|
||||||
prefetchStarted,
|
|
||||||
credentialsSource,
|
|
||||||
lastVisit: cachedSession?.lastVisit,
|
|
||||||
mailboxes: cachedSession?.mailboxes || []
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error checking session:", error);
|
console.error("Error checking session:", error);
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
|
|||||||
@ -127,22 +127,46 @@ export default function CourrierPage() {
|
|||||||
|
|
||||||
// Update account folders when mailboxes change
|
// Update account folders when mailboxes change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log('Mailboxes updated:', mailboxes);
|
||||||
setAccounts(prev => {
|
setAccounts(prev => {
|
||||||
const updated = [...prev];
|
const updated = [...prev];
|
||||||
if (updated[1]) {
|
if (updated[1]) {
|
||||||
updated[1].folders = mailboxes;
|
updated[1].folders = mailboxes;
|
||||||
}
|
}
|
||||||
|
console.log('Updated accounts with new mailboxes:', updated);
|
||||||
return updated;
|
return updated;
|
||||||
});
|
});
|
||||||
}, [mailboxes]);
|
}, [mailboxes]);
|
||||||
|
|
||||||
|
// Debug accounts state
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('Current accounts state:', accounts);
|
||||||
|
}, [accounts]);
|
||||||
|
|
||||||
// Calculate unread count (this would be replaced with actual data in production)
|
// Calculate unread count (this would be replaced with actual data in production)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Example: counting unread emails in the inbox
|
// Example: counting unread emails in the inbox
|
||||||
const unreadInInbox = (emails || []).filter(email => !email.read && currentFolder === 'INBOX').length;
|
const unreadInInbox = (emails || []).filter(email => {
|
||||||
|
// Access the 'read' property safely, handling both old and new email formats
|
||||||
|
return (!email.read && email.read !== undefined) ||
|
||||||
|
(email.flags && !email.flags.seen) ||
|
||||||
|
false;
|
||||||
|
}).filter(email => currentFolder === 'INBOX').length;
|
||||||
setUnreadCount(unreadInInbox);
|
setUnreadCount(unreadInInbox);
|
||||||
}, [emails, currentFolder]);
|
}, [emails, currentFolder]);
|
||||||
|
|
||||||
|
// Ensure accounts section is never empty
|
||||||
|
useEffect(() => {
|
||||||
|
// If accounts array becomes empty (bug), restore default accounts
|
||||||
|
if (!accounts || accounts.length === 0) {
|
||||||
|
console.warn('Accounts array is empty, restoring defaults');
|
||||||
|
setAccounts([
|
||||||
|
{ id: 0, name: 'All', email: '', color: 'bg-gray-500' },
|
||||||
|
{ id: 1, name: 'Loading...', email: '', color: 'bg-blue-500', folders: mailboxes }
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}, [accounts, mailboxes]);
|
||||||
|
|
||||||
// Initialize session and start prefetching
|
// Initialize session and start prefetching
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Flag to prevent multiple initialization attempts
|
// Flag to prevent multiple initialization attempts
|
||||||
@ -167,6 +191,18 @@ export default function CourrierPage() {
|
|||||||
const response = await fetch('/api/courrier/session');
|
const response = await fetch('/api/courrier/session');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
|
console.log('[DEBUG] Session API response:', {
|
||||||
|
authenticated: data.authenticated,
|
||||||
|
hasEmailCredentials: data.hasEmailCredentials,
|
||||||
|
email: data.email,
|
||||||
|
allAccountsExists: !!data.allAccounts,
|
||||||
|
allAccountsIsArray: Array.isArray(data.allAccounts),
|
||||||
|
allAccountsLength: data.allAccounts?.length || 0,
|
||||||
|
mailboxesExists: !!data.mailboxes,
|
||||||
|
mailboxesIsArray: Array.isArray(data.mailboxes),
|
||||||
|
mailboxesLength: data.mailboxes?.length || 0
|
||||||
|
});
|
||||||
|
|
||||||
if (!isMounted) return;
|
if (!isMounted) return;
|
||||||
|
|
||||||
if (data.authenticated) {
|
if (data.authenticated) {
|
||||||
@ -174,20 +210,45 @@ export default function CourrierPage() {
|
|||||||
console.log('Session initialized, prefetch status:', data.prefetchStarted ? 'running' : 'not started');
|
console.log('Session initialized, prefetch status:', data.prefetchStarted ? 'running' : 'not started');
|
||||||
setPrefetchStarted(Boolean(data.prefetchStarted));
|
setPrefetchStarted(Boolean(data.prefetchStarted));
|
||||||
|
|
||||||
// Update the accounts with the actual email address
|
// Update accounts with the default email as fallback
|
||||||
if (data.email) {
|
const updatedAccounts = [
|
||||||
setAccounts(prev => {
|
{ id: 0, name: 'All', email: '', color: 'bg-gray-500' }
|
||||||
const updated = [...prev];
|
];
|
||||||
updated[1] = {
|
|
||||||
...updated[1],
|
// Check if we have multiple accounts returned
|
||||||
name: data.email,
|
if (data.allAccounts && Array.isArray(data.allAccounts) && data.allAccounts.length > 0) {
|
||||||
email: data.email,
|
console.log('Multiple accounts found:', data.allAccounts.length);
|
||||||
folders: data.mailboxes || mailboxes
|
|
||||||
|
// Add each account from the server
|
||||||
|
data.allAccounts.forEach((account, index) => {
|
||||||
|
console.log(`[DEBUG] Processing account: ${account.email}, display_name: ${account.display_name}, has folders: ${!!data.mailboxes}`);
|
||||||
|
|
||||||
|
const accountWithFolders = {
|
||||||
|
id: account.id || index + 1,
|
||||||
|
name: account.display_name || account.email,
|
||||||
|
email: account.email,
|
||||||
|
color: account.color || 'bg-blue-500',
|
||||||
|
folders: data.mailboxes || []
|
||||||
};
|
};
|
||||||
return updated;
|
console.log(`[DEBUG] Adding account with ${accountWithFolders.folders.length} folders:`, accountWithFolders.folders);
|
||||||
|
updatedAccounts.push(accountWithFolders);
|
||||||
|
});
|
||||||
|
} else if (data.email) {
|
||||||
|
// Fallback to single account if allAccounts is not available
|
||||||
|
console.log(`[DEBUG] Fallback to single account: ${data.email}`);
|
||||||
|
|
||||||
|
updatedAccounts.push({
|
||||||
|
id: 1,
|
||||||
|
name: data.email,
|
||||||
|
email: data.email,
|
||||||
|
color: 'bg-blue-500',
|
||||||
|
folders: data.mailboxes || []
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('Setting accounts:', updatedAccounts);
|
||||||
|
setAccounts(updatedAccounts);
|
||||||
|
|
||||||
// Preload first page of emails for faster initial rendering
|
// Preload first page of emails for faster initial rendering
|
||||||
if (session?.user?.id) {
|
if (session?.user?.id) {
|
||||||
await loadEmails();
|
await loadEmails();
|
||||||
|
|||||||
1
db_query.sql
Normal file
1
db_query.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
SELECT * FROM "MailCredentials" LIMIT 5;
|
||||||
@ -248,8 +248,26 @@ export async function getEmails(
|
|||||||
console.log(`Cache miss for emails ${userId}:${folder}:${page}:${perPage}, fetching from IMAP`);
|
console.log(`Cache miss for emails ${userId}:${folder}:${page}:${perPage}, fetching from IMAP`);
|
||||||
|
|
||||||
const client = await getImapConnection(userId);
|
const client = await getImapConnection(userId);
|
||||||
|
let mailboxes: string[] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log(`[DEBUG] Fetching mailboxes for user ${userId}`);
|
||||||
|
// Get list of mailboxes first
|
||||||
|
try {
|
||||||
|
mailboxes = await getMailboxes(client);
|
||||||
|
console.log(`[DEBUG] Found ${mailboxes.length} mailboxes:`, mailboxes);
|
||||||
|
|
||||||
|
// Save mailboxes in session data
|
||||||
|
const cachedSession = await getCachedImapSession(userId);
|
||||||
|
await cacheImapSession(userId, {
|
||||||
|
...(cachedSession || { lastActive: Date.now() }),
|
||||||
|
mailboxes
|
||||||
|
});
|
||||||
|
console.log(`[DEBUG] Updated cached session with mailboxes for user ${userId}`);
|
||||||
|
} catch (mailboxError) {
|
||||||
|
console.error(`[ERROR] Failed to fetch mailboxes:`, mailboxError);
|
||||||
|
}
|
||||||
|
|
||||||
// Open mailbox
|
// Open mailbox
|
||||||
const mailboxData = await client.mailboxOpen(folder);
|
const mailboxData = await client.mailboxOpen(folder);
|
||||||
const totalMessages = mailboxData.exists;
|
const totalMessages = mailboxData.exists;
|
||||||
@ -262,14 +280,6 @@ export async function getEmails(
|
|||||||
|
|
||||||
// Empty result if no messages
|
// Empty result if no messages
|
||||||
if (totalMessages === 0 || from > to) {
|
if (totalMessages === 0 || from > to) {
|
||||||
const mailboxes = await getMailboxes(client);
|
|
||||||
|
|
||||||
// Cache mailbox list in session data
|
|
||||||
await cacheImapSession(userId, {
|
|
||||||
lastActive: Date.now(),
|
|
||||||
mailboxes
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
emails: [],
|
emails: [],
|
||||||
totalEmails: 0,
|
totalEmails: 0,
|
||||||
@ -414,14 +424,6 @@ export async function getEmails(
|
|||||||
// Sort by date, newest first
|
// Sort by date, newest first
|
||||||
emails.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
emails.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
||||||
|
|
||||||
const mailboxes = await getMailboxes(client);
|
|
||||||
|
|
||||||
// Cache mailbox list in session data
|
|
||||||
await cacheImapSession(userId, {
|
|
||||||
lastActive: Date.now(),
|
|
||||||
mailboxes
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
emails,
|
emails,
|
||||||
totalEmails: totalMessages,
|
totalEmails: totalMessages,
|
||||||
|
|||||||
@ -19,7 +19,7 @@ model User {
|
|||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
calendars Calendar[]
|
calendars Calendar[]
|
||||||
events Event[]
|
events Event[]
|
||||||
mailCredentials MailCredentials?
|
mailCredentials MailCredentials[]
|
||||||
webdavCredentials WebDAVCredentials?
|
webdavCredentials WebDAVCredentials?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ model Event {
|
|||||||
|
|
||||||
model MailCredentials {
|
model MailCredentials {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
userId String @unique
|
userId String
|
||||||
email String
|
email String
|
||||||
password String
|
password String
|
||||||
host String
|
host String
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user