import axios from 'axios'; export class RocketChatService { private apiUrl: string; private authToken: string; private userId: string; constructor() { // Extract the base URL from the iframe URL const baseUrl = process.env.NEXT_PUBLIC_IFRAME_PAROLE_URL?.split('/channel')[0] || ''; this.apiUrl = baseUrl; this.authToken = process.env.ROCKET_CHAT_TOKEN || ''; this.userId = process.env.ROCKET_CHAT_USER_ID || ''; } /** * Create a new channel in Rocket.Chat * @param mission The mission data * @returns Channel ID or throws error */ async createChannel(mission: any): Promise { try { // First, get all mission users that need to be added to the channel const missionUserEmails = mission.missionUsers.map((mu: any) => mu.user.email); const rocketChatUsernames: string[] = []; for (const email of missionUserEmails) { const user = await this.getUserByEmail(email); if (user) { rocketChatUsernames.push(user.username); } else { console.warn(`User not found in Rocket.Chat: ${email}`); } } // Sanitize the channel name to comply with Rocket.Chat restrictions const channelName = this.sanitizeChannelName(mission.name); // Create the channel const response = await axios.post( `${this.apiUrl}/api/v1/channels.create`, { name: channelName, members: rocketChatUsernames, readOnly: false }, { headers: { 'Content-Type': 'application/json', 'X-Auth-Token': this.authToken, 'X-User-Id': this.userId } } ); if (!response.data || !response.data.success) { throw new Error(`Failed to create Rocket.Chat channel: ${JSON.stringify(response.data)}`); } const channelId = response.data.channel._id; console.log(`Created Rocket.Chat channel with ID: ${channelId}`); // Make "Gardien de la Parole" users channel admins await this.setChannelAdmins(channelId, mission.missionUsers); return channelId; } catch (error) { console.error('Error creating Rocket.Chat channel:', error); throw new Error(`Rocket.Chat integration failed: ${error instanceof Error ? error.message : String(error)}`); } } /** * Make "Gardien de la Parole" users channel admins * @param channelId The Rocket.Chat channel ID * @param missionUsers The mission users with roles */ async setChannelAdmins(channelId: string, missionUsers: any[]): Promise { try { // Find "Gardien de la Parole" users const gardienParoleUsers = missionUsers.filter((mu: any) => mu.role === 'gardien-parole'); for (const gardienUser of gardienParoleUsers) { const user = await this.getUserByEmail(gardienUser.user.email); if (user) { await this.makeUserChannelOwner(channelId, user._id); } } } catch (error) { console.error('Error setting channel admins:', error); // Don't fail if setting admins fails } } /** * Make a user a channel owner * @param channelId The Rocket.Chat channel ID * @param userId The Rocket.Chat user ID */ async makeUserChannelOwner(channelId: string, userId: string): Promise { try { const response = await axios.post( `${this.apiUrl}/api/v1/channels.addOwner`, { roomId: channelId, userId: userId }, { headers: { 'Content-Type': 'application/json', 'X-Auth-Token': this.authToken, 'X-User-Id': this.userId } } ); if (!response.data || !response.data.success) { throw new Error(`Failed to make user channel owner: ${JSON.stringify(response.data)}`); } console.log(`Made user ${userId} an owner of channel ${channelId}`); } catch (error) { console.error(`Error making user ${userId} channel owner:`, error); // Don't fail if individual user assignment fails } } /** * Get a user by email * @param email The user email to search for * @returns The user object or null if not found */ async getUserByEmail(email: string): Promise { try { // First try exact email match const response = await axios.get( `${this.apiUrl}/api/v1/users.list`, { headers: { 'X-Auth-Token': this.authToken, 'X-User-Id': this.userId } } ); if (!response.data || !response.data.success) { throw new Error(`Failed to get users: ${JSON.stringify(response.data)}`); } // First check if user exists by email const userByEmail = response.data.users.find((user: any) => user.emails?.some((e: any) => e.address === email) ); if (userByEmail) { return userByEmail; } // If not found by email, try by username (username might be the part before @) const username = email.split('@')[0]; const userByUsername = response.data.users.find((user: any) => user.username === username); return userByUsername || null; } catch (error) { console.error('Error getting user by email:', error); return null; } } /** * Sanitize a channel name to comply with Rocket.Chat restrictions * @param name The original name * @returns The sanitized name */ private sanitizeChannelName(name: string): string { // Replace spaces and invalid characters with hyphens // Channel names must match regex [0-9a-zA-Z-_.]+ let sanitized = name.replace(/[^0-9a-zA-Z-_.]/g, '-'); // Ensure no sequential hyphens sanitized = sanitized.replace(/-+/g, '-'); // Trim hyphens from beginning and end sanitized = sanitized.replace(/^-+|-+$/g, ''); // Ensure name is not empty after sanitization if (!sanitized) { sanitized = 'mission-channel'; } return sanitized.toLowerCase(); } /** * Delete a channel from Rocket.Chat * @param channelId The Rocket.Chat channel ID to delete * @returns True if successful, false otherwise */ async deleteChannel(channelId: string): Promise { try { const response = await axios.post( `${this.apiUrl}/api/v1/channels.delete`, { roomId: channelId }, { headers: { 'Content-Type': 'application/json', 'X-Auth-Token': this.authToken, 'X-User-Id': this.userId } } ); return response.data && response.data.success === true; } catch (error) { console.error(`Error deleting Rocket.Chat channel ${channelId}:`, error); return false; } } }