221 lines
6.7 KiB
TypeScript
221 lines
6.7 KiB
TypeScript
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<string> {
|
|
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<void> {
|
|
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<void> {
|
|
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<any | null> {
|
|
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<boolean> {
|
|
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;
|
|
}
|
|
}
|
|
}
|