import { getServerSession } from "next-auth"; import { authOptions } from "@/app/api/auth/[...nextauth]/route"; import { NextResponse } from "next/server"; // Helper function to get user token using admin credentials async function getUserToken(baseUrl: string) { try { // Step 1: Use admin token to authenticate const adminHeaders = { 'X-Auth-Token': process.env.ROCKET_CHAT_TOKEN!, 'X-User-Id': process.env.ROCKET_CHAT_USER_ID!, 'Content-Type': 'application/json' }; // Step 2: Create user token using admin credentials const createTokenResponse = await fetch(`${baseUrl}/api/v1/users.createToken`, { method: 'POST', headers: adminHeaders }); if (!createTokenResponse.ok) { console.error('Failed to create user token:', createTokenResponse.status); return null; } const tokenData = await createTokenResponse.json(); return { authToken: tokenData.data.authToken, userId: tokenData.data.userId }; } catch (error) { console.error('Error getting user token:', error); return null; } } export async function GET(request: Request) { try { const session = await getServerSession(authOptions); if (!session?.user?.email) { console.error('No valid session or email found'); return NextResponse.json({ messages: [] }, { status: 200 }); } const baseUrl = process.env.NEXT_PUBLIC_IFRAME_PAROLE_URL?.split('/channel')[0]; if (!baseUrl) { console.error('Failed to get Rocket.Chat base URL'); return NextResponse.json({ error: 'Server configuration error' }, { status: 500 }); } console.log('Using Rocket.Chat base URL:', baseUrl); // Step 1: Use admin token to authenticate const adminHeaders = { 'X-Auth-Token': process.env.ROCKET_CHAT_TOKEN!, 'X-User-Id': process.env.ROCKET_CHAT_USER_ID!, 'Content-Type': 'application/json' }; // Step 2: Get the current user's Rocket.Chat ID const username = session.user.email.split('@')[0]; if (!username) { console.error('No username found in session email'); return NextResponse.json({ messages: [] }, { status: 200 }); } // Get all users to find the current user const usersResponse = await fetch(`${baseUrl}/api/v1/users.list`, { method: 'GET', headers: adminHeaders }); if (!usersResponse.ok) { console.error('Failed to get users list:', usersResponse.status); return NextResponse.json({ messages: [] }, { status: 200 }); } const usersData = await usersResponse.json(); console.log('Users list response:', { success: usersData.success, count: usersData.count, usersCount: usersData.users?.length }); // Find the current user in the list const currentUser = usersData.users.find((user: any) => user.username === username || user.emails?.some((email: any) => email.address === session.user.email) ); if (!currentUser) { console.error('User not found in users list'); return NextResponse.json({ messages: [] }, { status: 200 }); } console.log('Found Rocket.Chat user:', { username: currentUser.username, id: currentUser._id }); // Step 3: Login as the user to get their token const loginResponse = await fetch(`${baseUrl}/api/v1/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user: currentUser.username, password: process.env.ROCKET_CHAT_USER_PASSWORD // This should be the user's password or a shared password }) }); if (!loginResponse.ok) { console.error('Failed to login as user:', loginResponse.status); const errorText = await loginResponse.text(); console.error('Login error details:', errorText); return NextResponse.json({ messages: [] }, { status: 200 }); } const loginData = await loginResponse.json(); const userHeaders = { 'X-Auth-Token': loginData.data.authToken, 'X-User-Id': loginData.data.userId, 'Content-Type': 'application/json' }; // Step 4: Get user's subscriptions using user token const subscriptionsResponse = await fetch(`${baseUrl}/api/v1/subscriptions.get`, { method: 'GET', headers: userHeaders }); if (!subscriptionsResponse.ok) { console.error('Failed to get subscriptions:', subscriptionsResponse.status); return NextResponse.json({ messages: [] }, { status: 200 }); } const subscriptionsData = await subscriptionsResponse.json(); console.log('Subscriptions response:', { success: subscriptionsData.success, count: subscriptionsData.count, subscriptionsCount: subscriptionsData.subscriptions?.length, update: subscriptionsData.update, remove: subscriptionsData.remove }); if (!subscriptionsData.success || !Array.isArray(subscriptionsData.update)) { console.error('Invalid subscriptions response structure'); return NextResponse.json({ messages: [] }, { status: 200 }); } // Filter subscriptions for the current user const userSubscriptions = subscriptionsData.update.filter((sub: any) => { // For direct messages (t: 'd'), check if the room ID contains the user's ID if (sub.t === 'd') { return sub.rid.includes(currentUser._id); } // For channels (t: 'c'), include if user has unread messages or mentions return sub.t === 'c' && (sub.unread > 0 || sub.userMentions > 0 || sub.alert); }); console.log('Filtered subscriptions:', { total: userSubscriptions.length, roomTypes: userSubscriptions.map((sub: any) => ({ type: sub.t, name: sub.fname || sub.name, unread: sub.unread, mentions: sub.userMentions, alert: sub.alert })) }); const messages: any[] = []; const processedRooms = new Set(); // Step 5: Fetch messages using user token for (const subscription of userSubscriptions) { if (messages.length >= 7 || processedRooms.has(subscription._id)) continue; processedRooms.add(subscription._id); try { // Determine the correct endpoint based on room type const endpoint = subscription.t === 'c' ? 'channels.messages' : 'im.messages'; // Get the latest messages from the room const messagesResponse = await fetch( `${baseUrl}/api/v1/${endpoint}?roomId=${subscription.rid}&count=1`, { method: 'GET', headers: userHeaders }); if (!messagesResponse.ok) { console.error(`Failed to get messages for room ${subscription.name}:`, messagesResponse.status); const errorText = await messagesResponse.text(); console.error(`Messages error details for ${subscription.name}:`, errorText); continue; } const messageData = await messagesResponse.json(); console.log(`Messages for room ${subscription.name}:`, { success: messageData.success, count: messageData.count, hasMessages: messageData.messages?.length > 0 }); if (messageData.success && messageData.messages?.length > 0) { const message = messageData.messages[0]; messages.push({ id: message._id, text: message.msg, timestamp: message.ts, roomName: subscription.fname || subscription.name || 'Direct Message', roomType: subscription.t, unread: subscription.unread || 0, userMentions: subscription.userMentions || 0, alert: subscription.alert || false, lastSeen: subscription.ls, sender: { username: message.u.username, name: message.u.name || message.u.username, initials: (message.u.name || message.u.username || '') .split(' ') .map((n: string) => n[0]) .slice(0, 2) .join('') .toUpperCase(), color: message.u.username === currentUser.username ? '#E3E3E3' : getAvatarColor(message.u.username) }, isOwnMessage: message.u.username === currentUser.username, room: { id: subscription.rid, type: subscription.t, name: subscription.fname || subscription.name, isChannel: subscription.t === 'c', isDirect: subscription.t === 'd' } }); } } catch (error) { console.error(`Error fetching message for room ${subscription.name}:`, error); continue; } } // Sort messages by timestamp (newest first) and limit to 7 messages.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); const limitedMessages = messages.slice(0, 7); return NextResponse.json({ messages: limitedMessages, total: messages.length, hasMore: messages.length > 7 }, { status: 200 }); } catch (error) { console.error('Error in messages endpoint:', error); return NextResponse.json({ messages: [], total: 0, hasMore: false }, { status: 200 }); } } // Helper function to generate consistent avatar colors function getAvatarColor(username: string): string { const colors = [ '#FF7452', // Coral '#4CAF50', // Green '#2196F3', // Blue '#9C27B0', // Purple '#FF9800', // Orange '#00BCD4', // Cyan '#795548', // Brown '#607D8B' // Blue Grey ]; // Generate a consistent index based on username const index = username .split('') .reduce((acc, char) => acc + char.charCodeAt(0), 0) % colors.length; return colors[index]; }