missions api2

This commit is contained in:
alma 2025-05-06 17:14:37 +02:00
parent 926b8ff54f
commit 943ee01698
2 changed files with 46 additions and 139 deletions

3
.env
View File

@ -11,7 +11,8 @@ KEYCLOAK_ADMIN_PASSWORD=PW5jfqX00m
DOLIBARR_API_URL=https://mediations.slm-lab.net/api/index.php/
DOLIBARR_API_KEY=2znq976PzZz1q2JSe9DG2A3hmbNMGIh8
OUTLINE_API_KEY="ol_api_tlLlANBfcoJ4l7zA8GOcpduAeL6QyBTcYvEnlN"
OUTLINE_API_URL="https://chapitre.slm-lab.net/api"
# MinIO S3 configuration
MINIO_S3_UPLOAD_BUCKET_URL="https://dome-api.slm-lab.net/"
MINIO_AWS_REGION="eu-east-1"

View File

@ -5,28 +5,33 @@ export class OutlineService {
private apiToken: string;
constructor() {
this.apiUrl = process.env.OUTLINE_API_URL || '';
this.apiUrl = process.env.OUTLINE_API_URL || 'https://chapitre.slm-lab.net/api';
this.apiToken = process.env.OUTLINE_API_KEY || '';
console.log('OutlineService initialized with URL:', this.apiUrl);
console.log('Creating Outline collection with token length:', this.apiToken.length);
}
/**
* Create a new collection in Outline
* @param mission The mission data
* @returns Collection ID or throws error
*/
async createCollection(mission: any): Promise<string> {
if (!this.apiToken) {
throw new Error('Outline API token is not configured');
}
try {
// Log the API details for debugging
console.log('Creating Outline collection with token length:', this.apiToken ? this.apiToken.length : 0);
console.log('Outline API URL:', this.apiUrl);
// Create a collection in Outline based on the mission
const response = await axios.post(
`${this.apiUrl}/collections.create`,
`${this.apiUrl}/collections`,
{
name: mission.name,
description: mission.intention || '',
permission: 'read',
private: true
name: mission.label,
description: mission.description || 'Mission documentation',
color: '#4f46e5', // Indigo color as default
permission: 'read_write',
// Added extra fields that might be useful for identifying the collection
private: false,
external: true,
meta: {
missionId: mission.id,
createdAt: new Date().toISOString()
}
},
{
headers: {
@ -36,136 +41,37 @@ export class OutlineService {
}
);
if (!response.data || !response.data.data || !response.data.data.id) {
throw new Error(`Failed to create Outline collection: ${JSON.stringify(response.data)}`);
if (response.data && response.data.data && response.data.data.id) {
return response.data.data.id;
} else {
throw new Error('Failed to get collection ID from Outline API response');
}
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) {
if (axios.isAxiosError(error) && error.response) {
console.error('Outline API Error Details:', {
status: error.response.status,
statusText: error.response.statusText,
data: error.response.data
});
}
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;
if (axios.isAxiosError(error)) {
if (error.response?.status === 401) {
console.error('Outline authentication error:', error.response.data);
throw new Error('Outline API authentication failed - check your token');
} else if (error.response?.status === 429) {
console.error('Outline rate limit error:', error.response.data);
throw new Error('Outline API rate limit exceeded - try again later');
} else {
console.error('Outline API error:', error.response?.data || error.message);
throw new Error(`Outline API error: ${error.response?.status} - ${error.message}`);
}
// 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
throw error;
}
}
/**
* 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> {
if (!this.apiToken) {
throw new Error('Outline API token is not configured');
}
try {
const response = await axios.post(
`${this.apiUrl}/collections.delete`,
{
id: collectionId
},
// Delete the collection in Outline
await axios.delete(
`${this.apiUrl}/collections/${collectionId}`,
{
headers: {
'Content-Type': 'application/json',
@ -174,9 +80,9 @@ export class OutlineService {
}
);
return response.data && response.data.success === true;
return true;
} catch (error) {
console.error(`Error deleting Outline collection ${collectionId}:`, error);
console.error('Error deleting Outline collection:', error);
return false;
}
}