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: Create a token for the current user const createTokenResponse = await fetch(`${baseUrl}/api/v1/users.createToken`, { method: 'POST', headers: adminHeaders, body: JSON.stringify({ userId: currentUser._id }) }); if (!createTokenResponse.ok) { console.error('Failed to create user token:', createTokenResponse.status); const errorText = await createTokenResponse.text(); console.error('Create token error details:', errorText); return NextResponse.json({ messages: [] }, { status: 200 }); } const tokenData = await createTokenResponse.json(); // Use the user's token for subsequent requests const userHeaders = { 'X-Auth-Token': tokenData.data.authToken, 'X-User-Id': currentUser._id, '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); const errorText = await subscriptionsResponse.text(); console.error('Subscriptions error details:', errorText); return NextResponse.json({ messages: [] }, { status: 200 }); } const subscriptionsData = await subscriptionsResponse.json(); console.log('Subscriptions response:', subscriptionsData); 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 all channels return sub.t === 'c'; }); 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 using user token 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]; const messageUser = message.u || {}; const username = messageUser.username || subscription.name || 'unknown'; const displayName = subscription.fname || subscription.name || username; // Format the timestamp const timestamp = new Date(message.ts); const now = new Date(); let formattedTime = ''; if (isNaN(timestamp.getTime())) { formattedTime = 'Invalid Date'; } else if (timestamp.toDateString() === now.toDateString()) { // Today - show time only formattedTime = timestamp.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' }); } else { // Not today - show date formattedTime = timestamp.toLocaleDateString('fr-FR', { day: '2-digit', month: 'short' }); } // Create initials from display name const initials = displayName .split(' ') .map((n: string) => n[0]) .slice(0, 2) .join('') .toUpperCase(); messages.push({ id: message._id, text: message.msg || '', timestamp: formattedTime, roomName: displayName, roomType: subscription.t, unread: subscription.unread || 0, userMentions: subscription.userMentions || 0, alert: subscription.alert || false, lastSeen: subscription.ls, u: { // Add back the u object that the component expects _id: messageUser._id || subscription.u?._id, username: username, name: displayName }, sender: { _id: messageUser._id || subscription.u?._id, username: username, name: displayName, initials: initials, color: getAvatarColor(username) }, isOwnMessage: username === currentUser.username, room: { id: subscription.rid, type: subscription.t, name: displayName, isChannel: subscription.t === 'c', isDirect: subscription.t === 'd', link: subscription.t === 'c' ? `${baseUrl}/channel/${subscription.name}` : `${baseUrl}/direct/${subscription.name}` } }); } } 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) => { const dateA = new Date(a.timestamp); const dateB = new Date(b.timestamp); return dateB.getTime() - dateA.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]; }