solve mail backend 11

This commit is contained in:
alma 2025-04-17 14:14:15 +02:00
parent 43abed23ab
commit a2ef35aa29
3 changed files with 58 additions and 148 deletions

View File

@ -135,104 +135,17 @@ export const authOptions: NextAuthOptions = {
return false;
}
},
async jwt({ token, account, profile }) {
if (account && profile) {
token.accessToken = account.access_token ?? '';
token.refreshToken = account.refresh_token ?? '';
token.accessTokenExpires = (account.expires_at ?? 0) * 1000;
token.role = (profile as any).groups ?? [];
token.username = (profile as any).preferred_username ?? profile.email?.split('@')[0] ?? '';
token.first_name = (profile as any).given_name ?? '';
token.last_name = (profile as any).family_name ?? '';
}
// Return previous token if not expired
if (Date.now() < (token.accessTokenExpires as number)) {
return token;
}
try {
const clientId = getRequiredEnvVar("KEYCLOAK_CLIENT_ID");
const clientSecret = getRequiredEnvVar("KEYCLOAK_CLIENT_SECRET");
const response = await fetch(
`${process.env.KEYCLOAK_BASE_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/token`,
{
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "refresh_token",
client_id: clientId,
client_secret: clientSecret,
refresh_token: token.refreshToken as string,
}),
}
);
const tokens = await response.json();
if (!response.ok) {
throw new Error("RefreshAccessTokenError");
}
return {
...token,
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token ?? token.refreshToken,
accessTokenExpires: Date.now() + tokens.expires_in * 1000,
};
} catch (error) {
return {
...token,
error: "RefreshAccessTokenError",
};
}
},
async session({ session, token }) {
if (token.error) {
throw new Error("RefreshAccessTokenError");
if (session?.user && token.sub) {
session.user.id = token.sub;
}
try {
console.log('Creating/updating user in session callback:', {
id: token.sub,
email: token.email
});
// Create or update user in local database
await prisma.user.upsert({
where: { id: token.sub as string },
update: {
email: token.email as string,
password: '', // We don't store password for Keycloak users
},
create: {
id: token.sub as string,
email: token.email as string,
password: '', // We don't store password for Keycloak users
},
});
console.log('User created/updated successfully');
} catch (error) {
console.error('Error creating/updating user in session callback:', error);
}
session.accessToken = token.accessToken;
session.user = {
id: token.sub as string,
name: token.name,
email: token.email,
image: null,
username: token.username ?? '',
first_name: token.first_name ?? '',
last_name: token.last_name ?? '',
role: token.role ?? [],
};
return session;
},
async jwt({ token, user, account }) {
if (user) {
token.sub = user.id;
}
return token;
}
},
pages: {

View File

@ -14,6 +14,7 @@ export async function GET() {
);
}
// Get credentials from database
const credentials = await prisma.mailCredentials.findUnique({
where: {
userId: session.user.id
@ -27,38 +28,34 @@ export async function GET() {
);
}
let client;
try {
client = new ImapFlow({
host: credentials.host,
port: credentials.port,
secure: true,
auth: {
user: credentials.email,
pass: credentials.password,
},
logger: false,
emitLogs: false,
tls: {
rejectUnauthorized: false // Allow self-signed certificates
}
});
// Connect to IMAP server
const client = new ImapFlow({
host: credentials.host,
port: credentials.port,
secure: true,
auth: {
user: credentials.email,
pass: credentials.password,
},
logger: false,
emitLogs: false,
tls: {
rejectUnauthorized: false
}
});
try {
await client.connect();
const mailbox = await client.mailboxOpen('INBOX');
// Fetch the last 20 messages
// Fetch only essential message data
const messages = await client.fetch('1:20', {
envelope: true,
bodyStructure: true,
flags: true
});
const result = [];
for await (const message of messages) {
// Get the message body
const body = await client.download(message.uid.toString(), 'TEXT');
result.push({
id: message.uid.toString(),
from: message.envelope.from[0].address,
@ -66,46 +63,20 @@ export async function GET() {
date: message.envelope.date.toISOString(),
read: message.flags.has('\\Seen'),
starred: message.flags.has('\\Flagged'),
folder: mailbox.path,
// Additional fields that might be useful
to: message.envelope.to?.map(addr => addr.address).join(', ') || '',
cc: message.envelope.cc?.map(addr => addr.address) || [],
bcc: message.envelope.bcc?.map(addr => addr.address) || [],
flags: Array.from(message.flags),
body: body?.content?.toString() || ''
folder: mailbox.path
});
}
return NextResponse.json(result);
} catch (error) {
console.error('Mail API error:', error);
if (error instanceof Error) {
if (error.message.includes('Invalid login')) {
return NextResponse.json(
{ error: 'Invalid email credentials. Please update your email settings.' },
{ status: 401 }
);
}
return NextResponse.json(
{ error: `Failed to fetch emails: ${error.message}` },
{ status: 500 }
);
}
return NextResponse.json(
{ error: 'Failed to fetch emails' },
{ status: 500 }
);
} finally {
if (client) {
try {
await client.logout();
} catch (e) {
console.error('Error during logout:', e);
}
try {
await client.logout();
} catch (e) {
console.error('Error during logout:', e);
}
}
} catch (error) {
console.error('Unexpected error:', error);
console.error('Error in mail route:', error);
return NextResponse.json(
{ error: 'An unexpected error occurred' },
{ status: 500 }

View File

@ -0,0 +1,26 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
try {
const credentials = await prisma.mailCredentials.findMany({
select: {
id: true,
email: true,
host: true,
port: true,
userId: true
}
});
console.log('Mail Credentials:');
console.log(JSON.stringify(credentials, null, 2));
} catch (error) {
console.error('Error:', error);
} finally {
await prisma.$disconnect();
}
}
main();