import { prisma } from '@/lib/prisma'; import { LeantimeService } from './leantime-service'; import { OutlineService } from './outline-service'; import { RocketChatService } from './rocketchat-service'; interface IntegrationResult { success: boolean; error?: string; data?: { leantimeProjectId?: number; outlineCollectionId?: string; rocketChatChannelId?: string; giteaRepositoryUrl?: string; penpotProjectId?: string; }; } export class IntegrationService { private leantimeService: LeantimeService; private outlineService: OutlineService; private rocketChatService: RocketChatService; constructor() { this.leantimeService = new LeantimeService(); this.outlineService = new OutlineService(); this.rocketChatService = new RocketChatService(); } /** * Set up all integrations for a mission * @param missionId The mission ID * @returns Integration result */ async setupIntegrationsForMission(missionId: string): Promise { try { // Get complete mission data with users const mission = await prisma.mission.findUnique({ where: { id: missionId }, include: { missionUsers: { include: { user: true } }, attachments: true } }); if (!mission) { throw new Error(`Mission not found: ${missionId}`); } // These fields will store the IDs of created resources let leantimeProjectId: number | undefined; let outlineCollectionId: string | undefined; let rocketChatChannelId: string | undefined; try { // Step 1: Create Leantime project leantimeProjectId = await this.leantimeService.createProject(mission); console.log(`Leantime project created with ID: ${leantimeProjectId}`); // Step 2: Create Outline collection outlineCollectionId = await this.outlineService.createCollection(mission); console.log(`Outline collection created with ID: ${outlineCollectionId}`); // Step 3: Create Rocket.Chat channel rocketChatChannelId = await this.rocketChatService.createChannel(mission); console.log(`Rocket.Chat channel created with ID: ${rocketChatChannelId}`); // Add integrations for specific services if (mission.services.includes('gite')) { // TODO: Add Gitea integration when API docs are available console.log('Gitea service requested but integration not implemented yet'); } if (mission.services.includes('artlab')) { // TODO: Add Penpot integration when API docs are available console.log('Artlab service requested but integration not implemented yet'); } // Update the mission with the integration IDs await prisma.mission.update({ where: { id: missionId }, data: { leantimeProjectId: leantimeProjectId.toString(), outlineCollectionId: outlineCollectionId, rocketChatChannelId: rocketChatChannelId, // giteaRepositoryUrl and penpotProjectId will be added when implemented } }); return { success: true, data: { leantimeProjectId, outlineCollectionId, rocketChatChannelId } }; } catch (error) { console.error('Error setting up integrations:', error); // Rollback any created resources await this.rollbackIntegrations(leantimeProjectId, outlineCollectionId, rocketChatChannelId); // Delete the mission itself since an integration failed await prisma.mission.delete({ where: { id: missionId } }); return { success: false, error: `Integration failed: ${error instanceof Error ? error.message : String(error)}` }; } } catch (error) { console.error('Error in integration setup:', error); return { success: false, error: `Integration setup failed: ${error instanceof Error ? error.message : String(error)}` }; } } /** * Rollback integrations if any step fails * @param leantimeProjectId The Leantime project ID to delete * @param outlineCollectionId The Outline collection ID to delete * @param rocketChatChannelId The Rocket.Chat channel ID to delete */ private async rollbackIntegrations( leantimeProjectId?: number, outlineCollectionId?: string, rocketChatChannelId?: string ): Promise { try { // Attempt to delete Leantime project if (leantimeProjectId) { await this.leantimeService.deleteProject(leantimeProjectId); } // Attempt to delete Outline collection if (outlineCollectionId) { await this.outlineService.deleteCollection(outlineCollectionId); } // Attempt to delete Rocket.Chat channel if (rocketChatChannelId) { await this.rocketChatService.deleteChannel(rocketChatChannelId); } } catch (error) { console.error('Error during rollback:', error); // Even if rollback fails, we continue with mission deletion } } }