NeahNew/lib/services/outline-service.ts
2025-05-06 15:36:15 +02:00

172 lines
5.2 KiB
TypeScript

import axios from 'axios';
export class OutlineService {
private apiUrl: string;
private apiToken: string;
constructor() {
this.apiUrl = process.env.OUTLINE_API_URL || 'https://app.getoutline.com/api';
this.apiToken = process.env.OUTLINE_API_KEY || '';
}
/**
* Create a new collection in Outline
* @param mission The mission data
* @returns Collection ID or throws error
*/
async createCollection(mission: any): Promise<string> {
try {
const response = await axios.post(
`${this.apiUrl}/collections.create`,
{
name: mission.name,
description: mission.intention || '',
permission: 'read',
private: true
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiToken}`
}
}
);
if (!response.data || !response.data.data || !response.data.data.id) {
throw new Error(`Failed to create Outline collection: ${JSON.stringify(response.data)}`);
}
const collectionId = response.data.data.id;
console.log(`Created Outline collection with ID: ${collectionId}`);
// Assign users to the collection
if (mission.missionUsers && mission.missionUsers.length > 0) {
await this.assignUsersToCollection(collectionId, mission.missionUsers);
}
return collectionId;
} catch (error) {
console.error('Error creating Outline collection:', error);
throw new Error(`Outline integration failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Assign mission users to the Outline collection
* @param collectionId The Outline collection ID
* @param missionUsers The mission users with roles
*/
async assignUsersToCollection(collectionId: string, missionUsers: any[]): Promise<void> {
try {
for (const missionUser of missionUsers) {
// Get the user in Outline
const outlineUserId = await this.getUserByEmail(missionUser.user.email);
if (!outlineUserId) {
console.warn(`User not found in Outline: ${missionUser.user.email}`);
continue;
}
// Determine permission (Gardien de la Mémoire gets admin, others get read)
const permission = missionUser.role === 'gardien-memoire' ? 'admin' : 'read';
// Add the user to the collection
await this.addUserToCollection(collectionId, outlineUserId, permission);
}
} catch (error) {
console.error('Error assigning users to collection:', error);
// Continue even if some user assignments fail
}
}
/**
* Add a user to a collection with the specified permission
* @param collectionId The Outline collection ID
* @param userId The Outline user ID
* @param permission The permission to assign
*/
async addUserToCollection(collectionId: string, userId: string, permission: 'read' | 'admin'): Promise<void> {
try {
const response = await axios.post(
`${this.apiUrl}/collections.add_user`,
{
id: collectionId,
userId: userId,
permission: permission
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiToken}`
}
}
);
if (!response.data || !response.data.success) {
throw new Error(`Failed to add user to collection: ${JSON.stringify(response.data)}`);
}
console.log(`Added user ${userId} to collection ${collectionId} with permission ${permission}`);
} catch (error) {
console.error(`Error adding user ${userId} to collection ${collectionId}:`, error);
// Don't fail if individual user assignment fails
}
}
/**
* Get a user ID by email
* @param email The user email to search for
* @returns The user ID or null if not found
*/
async getUserByEmail(email: string): Promise<string | null> {
try {
const response = await axios.post(
`${this.apiUrl}/users.info`,
{
email: email
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiToken}`
}
}
);
if (!response.data || !response.data.data || !response.data.data.id) {
return null;
}
return response.data.data.id;
} catch (error) {
console.error('Error getting user by email:', error);
return null;
}
}
/**
* Delete a collection from Outline
* @param collectionId The Outline collection ID to delete
* @returns True if successful, false otherwise
*/
async deleteCollection(collectionId: string): Promise<boolean> {
try {
const response = await axios.post(
`${this.apiUrl}/collections.delete`,
{
id: collectionId
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiToken}`
}
}
);
return response.data && response.data.success === true;
} catch (error) {
console.error(`Error deleting Outline collection ${collectionId}:`, error);
return false;
}
}
}