import { NotificationAdapter } from './notification-adapter.interface'; import { getServerSession } from 'next-auth'; import { authOptions } from "@/app/api/auth/options"; import { logger } from '@/lib/logger'; import { Notification, NotificationCount } from '@/lib/types/notification'; export class RocketChatAdapter implements NotificationAdapter { readonly sourceName = 'rocketchat'; private baseUrl: string; constructor() { this.baseUrl = process.env.NEXT_PUBLIC_IFRAME_PAROLE_URL?.split('/channel')[0] || ''; logger.debug('[ROCKETCHAT_ADAPTER] Initialized', { hasBaseUrl: !!this.baseUrl, }); } async isConfigured(): Promise { return !!this.baseUrl && !!process.env.ROCKET_CHAT_TOKEN && !!process.env.ROCKET_CHAT_USER_ID; } /** * Get user's email from session */ private async getUserEmail(): Promise { try { const session = await getServerSession(authOptions); const email = session?.user?.email || null; logger.debug('[ROCKETCHAT_ADAPTER] getUserEmail', { hasSession: !!session, hasEmail: !!email, emailHash: email ? Buffer.from(email.toLowerCase()).toString('base64').slice(0, 12) : null, }); return email; } catch (error) { logger.error('[ROCKETCHAT_ADAPTER] Error getting user email', { error: error instanceof Error ? error.message : String(error), }); return null; } } /** * Get RocketChat user ID from email */ private async getRocketChatUserId(email: string): Promise { try { const username = email.split('@')[0]; if (!username) return null; const adminHeaders = { 'X-Auth-Token': process.env.ROCKET_CHAT_TOKEN!, 'X-User-Id': process.env.ROCKET_CHAT_USER_ID!, 'Content-Type': 'application/json' }; const usersResponse = await fetch(`${this.baseUrl}/api/v1/users.list`, { method: 'GET', headers: adminHeaders }); if (!usersResponse.ok) { logger.error('[ROCKETCHAT_ADAPTER] Failed to get users list', { status: usersResponse.status, }); return null; } const usersData = await usersResponse.json(); if (!usersData.success || !Array.isArray(usersData.users)) { logger.error('[ROCKETCHAT_ADAPTER] Invalid users list response', { success: usersData.success, hasUsers: Array.isArray(usersData.users), }); return null; } logger.debug('[ROCKETCHAT_ADAPTER] Searching for user', { username, totalUsers: usersData.users.length, }); const currentUser = usersData.users.find((u: any) => u.username === username); if (!currentUser) { logger.warn('[ROCKETCHAT_ADAPTER] User not found in RocketChat', { username, searchedIn: usersData.users.length, availableUsernames: usersData.users.slice(0, 5).map((u: any) => u.username), }); return null; } logger.debug('[ROCKETCHAT_ADAPTER] Found user', { username, userId: currentUser._id, }); return currentUser._id; } catch (error) { logger.error('[ROCKETCHAT_ADAPTER] Error getting RocketChat user ID', { error: error instanceof Error ? error.message : String(error), }); return null; } } /** * Get user token for RocketChat API * Creates a token for the specified RocketChat user ID */ private async getUserToken(rocketChatUserId: string): Promise<{ authToken: string; userId: string } | null> { try { const adminHeaders = { 'X-Auth-Token': process.env.ROCKET_CHAT_TOKEN!, 'X-User-Id': process.env.ROCKET_CHAT_USER_ID!, 'Content-Type': 'application/json' }; // Create token for the specific user const createTokenResponse = await fetch(`${this.baseUrl}/api/v1/users.createToken`, { method: 'POST', headers: adminHeaders, body: JSON.stringify({ userId: rocketChatUserId }) }); if (!createTokenResponse.ok) { logger.error('[ROCKETCHAT_ADAPTER] Failed to create user token', { status: createTokenResponse.status, rocketChatUserId, }); return null; } const tokenData = await createTokenResponse.json(); if (!tokenData.success || !tokenData.data) { logger.error('[ROCKETCHAT_ADAPTER] Invalid token response', { response: tokenData, }); return null; } logger.debug('[ROCKETCHAT_ADAPTER] User token created', { rocketChatUserId, tokenUserId: tokenData.data.userId, }); return { authToken: tokenData.data.authToken, userId: tokenData.data.userId }; } catch (error) { logger.error('[ROCKETCHAT_ADAPTER] Error getting user token', { error: error instanceof Error ? error.message : String(error), rocketChatUserId, }); return null; } } async getNotificationCount(userId: string): Promise { logger.debug('[ROCKETCHAT_ADAPTER] getNotificationCount called', { userId }); try { const email = await this.getUserEmail(); if (!email) { logger.error('[ROCKETCHAT_ADAPTER] Could not get user email'); return { total: 0, unread: 0, sources: { rocketchat: { total: 0, unread: 0 } } }; } const rocketChatUserId = await this.getRocketChatUserId(email); if (!rocketChatUserId) { logger.debug('[ROCKETCHAT_ADAPTER] User not found in RocketChat', { emailHash: email ? Buffer.from(email.toLowerCase()).toString('base64').slice(0, 12) : null, }); return { total: 0, unread: 0, sources: { rocketchat: { total: 0, unread: 0 } } }; } logger.debug('[ROCKETCHAT_ADAPTER] Found RocketChat user', { rocketChatUserId, emailHash: Buffer.from(email.toLowerCase()).toString('base64').slice(0, 12), }); const userToken = await this.getUserToken(rocketChatUserId); if (!userToken) { logger.error('[ROCKETCHAT_ADAPTER] Could not get user token', { rocketChatUserId, }); return { total: 0, unread: 0, sources: { rocketchat: { total: 0, unread: 0 } } }; } const userHeaders = { 'X-Auth-Token': userToken.authToken, 'X-User-Id': userToken.userId, 'Content-Type': 'application/json' }; // Get user's subscriptions const subscriptionsResponse = await fetch(`${this.baseUrl}/api/v1/subscriptions.get`, { method: 'GET', headers: userHeaders }); if (!subscriptionsResponse.ok) { logger.error('[ROCKETCHAT_ADAPTER] Failed to get subscriptions', { status: subscriptionsResponse.status, }); return { total: 0, unread: 0, sources: { rocketchat: { total: 0, unread: 0 } } }; } const subscriptionsData = await subscriptionsResponse.json(); if (!subscriptionsData.success || !Array.isArray(subscriptionsData.update)) { logger.error('[ROCKETCHAT_ADAPTER] Invalid subscriptions response'); return { total: 0, unread: 0, sources: { rocketchat: { total: 0, unread: 0 } } }; } // Filter subscriptions with unread messages const userSubscriptions = subscriptionsData.update.filter((sub: any) => { return (sub.unread > 0 || sub.alert) && ['d', 'c', 'p'].includes(sub.t); }); // Calculate total unread count const totalUnreadCount = userSubscriptions.reduce((sum: number, sub: any) => sum + (sub.unread || 0), 0); logger.debug('[ROCKETCHAT_ADAPTER] Notification counts', { total: userSubscriptions.length, unread: totalUnreadCount, }); return { total: userSubscriptions.length, unread: totalUnreadCount, sources: { rocketchat: { total: userSubscriptions.length, unread: totalUnreadCount } } }; } catch (error) { logger.error('[ROCKETCHAT_ADAPTER] Error getting notification count', { error: error instanceof Error ? error.message : String(error), }); return { total: 0, unread: 0, sources: { rocketchat: { total: 0, unread: 0 } } }; } } async getNotifications(userId: string, page = 1, limit = 20): Promise { // For now, return empty array - we can implement this later if needed // The notification count is what matters for the badge return []; } async markAsRead(userId: string, notificationId: string): Promise { // Not implemented yet - RocketChat handles read status automatically return false; } async markAllAsRead(userId: string): Promise { // Not implemented yet - RocketChat handles read status automatically return false; } }