172 lines
5.2 KiB
TypeScript
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;
|
|
}
|
|
}
|
|
}
|